Skip to content

Commit

Permalink
Merge branch 'dev' into be-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
brettelliot committed Dec 18, 2024
2 parents 72c5742 + cac64a2 commit 7682986
Show file tree
Hide file tree
Showing 29 changed files with 225 additions and 239 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,11 @@ To run this example strategy, click on the `Deploy to Render` button below to de

If you want to contribute to Lumibot, you can check how to get started below. We are always looking for contributors to help us out!

Here's a video to help you get started with contributing to Lumibot: [Watch The Video](https://youtu.be/Huz6VxqafZs)

**Steps to contribute:**

0. Watch the video: [Watch The Video](https://youtu.be/Huz6VxqafZs)
1. Clone the repository to your local machine
2. Create a new branch for your feature
3. Run `pip install -r requirements_dev.txt` to install the developer dependencies
Expand Down
8 changes: 7 additions & 1 deletion lumibot/backtesting/backtesting_broker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from decimal import Decimal
from functools import wraps

import pandas as pd
import pytz

from lumibot.brokers import Broker
from lumibot.data_sources import DataSourceBacktesting
Expand Down Expand Up @@ -88,13 +88,19 @@ def get_historical_account_value(self):
def _update_datetime(self, update_dt, cash=None, portfolio_value=None):
"""Works with either timedelta or datetime input
and updates the datetime of the broker"""
tz = self.datetime.tzinfo
is_pytz = isinstance(tz, (pytz.tzinfo.StaticTzInfo, pytz.tzinfo.DstTzInfo))

if isinstance(update_dt, timedelta):
new_datetime = self.datetime + update_dt
elif isinstance(update_dt, int) or isinstance(update_dt, float):
new_datetime = self.datetime + timedelta(seconds=update_dt)
else:
new_datetime = update_dt

# This is needed to handle Daylight Savings Time changes
new_datetime = tz.normalize(new_datetime) if is_pytz else new_datetime

self.data_source._update_datetime(new_datetime, cash=cash, portfolio_value=portfolio_value)
if self.option_source:
self.option_source._update_datetime(new_datetime, cash=cash, portfolio_value=portfolio_value)
Expand Down
4 changes: 2 additions & 2 deletions lumibot/brokers/alpaca.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ def _submit_order(self, order):
order.set_identifier(response.id)
order.status = response.status
order.update_raw(response)
self._unprocessed_orders.append(order)

except Exception as e:
order.set_error(e)
Expand Down Expand Up @@ -547,14 +548,13 @@ def _run_stream(self):
"""

async def _trade_update(trade_update):
self._orders_queue.join()
try:
logged_order = trade_update.order
type_event = trade_update.event
identifier = logged_order.id
stored_order = self.get_tracked_order(identifier)
if stored_order is None:
logging.info(f"Untracked order {identifier} was logged by broker {self.name}")
logging.debug(f"Untracked order {identifier} was logged by broker {self.name}")
return False

price = trade_update.price
Expand Down
10 changes: 5 additions & 5 deletions lumibot/brokers/broker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1204,21 +1204,21 @@ def _process_trade_event(self, stored_order, type_event, price=None, filled_quan
except ValueError:
raise error

if type_event == self.NEW_ORDER:
if Order.is_equivalent_status(type_event, self.NEW_ORDER):
stored_order = self._process_new_order(stored_order)
self._on_new_order(stored_order)
elif type_event == self.CANCELED_ORDER:
elif Order.is_equivalent_status(type_event, self.CANCELED_ORDER):
# Do not cancel or re-cancel already completed orders
if stored_order.is_active():
stored_order = self._process_canceled_order(stored_order)
self._on_canceled_order(stored_order)
elif type_event == self.PARTIALLY_FILLED_ORDER:
elif Order.is_equivalent_status(type_event, self.PARTIALLY_FILLED_ORDER):
stored_order, position = self._process_partially_filled_order(stored_order, price, filled_quantity)
self._on_partially_filled_order(position, stored_order, price, filled_quantity, multiplier)
elif type_event == self.FILLED_ORDER:
elif Order.is_equivalent_status(type_event, self.FILLED_ORDER):
position = self._process_filled_order(stored_order, price, filled_quantity)
self._on_filled_order(position, stored_order, price, filled_quantity, multiplier)
elif type_event == self.CASH_SETTLED:
elif Order.is_equivalent_status(type_event, self.CASH_SETTLED):
self._process_cash_settlement(stored_order, price, filled_quantity)
stored_order.type = self.CASH_SETTLED
else:
Expand Down
7 changes: 5 additions & 2 deletions lumibot/brokers/ccxt.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ def _parse_broker_order(self, response, strategy_name, strategy_object=None):
response["side"],
limit_price=response["price"],
stop_price=response["stopPrice"],
time_in_force=response["timeInForce"].lower(),
time_in_force=response["timeInForce"].lower() if response["timeInForce"] else None,
quote=Asset(
symbol=pair[1],
asset_type="crypto",
Expand All @@ -324,7 +324,10 @@ def _pull_broker_order(self, identifier):
def _pull_broker_closed_orders(self):
params = {}

if self.is_margin_enabled():
if self.api.id == "kraken": # Check if the exchange is Kraken
logging.info("Detected Kraken exchange. Not sending params for closed orders.")
params = None # Ensure no parameters are sent
elif self.is_margin_enabled():
params["tradeType"] = "MARGIN_TRADE"

closed_orders = self.api.fetch_closed_orders(params)
Expand Down
4 changes: 1 addition & 3 deletions lumibot/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,7 @@ def find_and_load_dotenv(base_dir) -> bool:
# Add ALPACA_API_KEY, ALPACA_API_SECRET, and ALPACA_IS_PAPER to your .env file or set them as secrets
"API_KEY": os.environ.get("ALPACA_API_KEY"),
"API_SECRET": os.environ.get("ALPACA_API_SECRET"),
"PAPER": os.environ.get("ALPACA_IS_PAPER").lower() == "true"
if os.environ.get("ALPACA_IS_PAPER")
else True,
"PAPER": os.environ.get("ALPACA_IS_PAPER").lower() == "true" if os.environ.get("ALPACA_IS_PAPER") else True,
}

# Tradier Configuration
Expand Down
Loading

0 comments on commit 7682986

Please sign in to comment.