Skip to content

Commit

Permalink
Use logger for everything instead of logging to discord
Browse files Browse the repository at this point in the history
  • Loading branch information
brettelliot committed Dec 5, 2024
1 parent 0122f2d commit 6958933
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 41 deletions.
47 changes: 21 additions & 26 deletions lumibot/components/drift_rebalancer_logic.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from abc import ABC, abstractmethod
from typing import Dict, Any
from decimal import Decimal, ROUND_DOWN
import time
Expand All @@ -7,6 +6,7 @@

from lumibot.strategies.strategy import Strategy
from lumibot.entities.order import Order
from lumibot.tools.pandas import prettify_dataframe_with_decimals


class DriftType:
Expand Down Expand Up @@ -123,7 +123,7 @@ def __init__(
*,
strategy: Strategy,
drift_type: DriftType = DriftType.ABSOLUTE,
drift_threshold: Decimal = Decimal("0.05")
drift_threshold: Decimal = Decimal("0.05"),
) -> None:
self.strategy = strategy
self.drift_type = drift_type
Expand All @@ -133,7 +133,7 @@ def __init__(
def calculate(self, target_weights: Dict[str, Decimal]) -> pd.DataFrame:

if self.drift_type == DriftType.ABSOLUTE:
# The absolute value of all of the weights are less than the drift_threshold
# The absolute value of all the weights are less than the drift_threshold
# then we will never trigger a rebalance.

if all([abs(weight) < self.drift_threshold for weight in target_weights.values()]):
Expand Down Expand Up @@ -230,15 +230,15 @@ def _calculate_drift_row(self, row: pd.Series) -> Decimal:
return Decimal(-1)

elif row["current_quantity"] == Decimal(0) and row["target_weight"] > Decimal(0):
# We don't have any of this asset but we wanna buy some.
# We don't have any of this asset, but we want to buy some.
return Decimal(1)

elif row["current_quantity"] == Decimal(0) and row["target_weight"] == Decimal(-1):
# Should we short everything we have
return Decimal(-1)

elif row["current_quantity"] == Decimal(0) and row["target_weight"] < Decimal(0):
# We don't have any of this asset but we wanna short some.
# We don't have any of this asset, but we want to short some.
return Decimal(-1)

# Otherwise we just need to adjust our holding. Calculate the drift.
Expand Down Expand Up @@ -285,6 +285,10 @@ def rebalance(self, drift_df: pd.DataFrame = None) -> bool:
if drift_df is None:
raise ValueError("You must pass in a DataFrame to DriftOrderLogic.rebalance()")

# Just print the drift_df to the log but sort it by symbol column
drift_df = drift_df.sort_values(by='symbol')
self.strategy.logger.info(f"drift_df:\n{prettify_dataframe_with_decimals(df=drift_df)}")

rebalance_needed = self._check_if_rebalance_needed(drift_df)
if rebalance_needed:
self._rebalance(drift_df)
Expand Down Expand Up @@ -336,17 +340,13 @@ def _rebalance(self, df: pd.DataFrame = None) -> None:
)
sell_orders.append(order)

msg = "\nSubmitted sell orders:"
for order in sell_orders:
msg += f"\n{order}"
if sell_orders:
self.strategy.logger.info(msg)
self.strategy.log_message(msg, broadcast=True)

if not self.strategy.is_backtesting:
# Sleep to allow sell orders to fill
time.sleep(self.fill_sleeptime)

for order in sell_orders:
self.strategy.logger.info(f"Submitted sell order: {order}")

# Get current cash position from the broker
cash_position = self.get_current_cash_position()

Expand All @@ -365,14 +365,12 @@ def _rebalance(self, df: pd.DataFrame = None) -> None:
cash_position -= min(order_value, cash_position)
else:
self.strategy.logger.info(
f"Ran out of cash to buy {symbol}. Cash: {cash_position} and limit_price: {limit_price:.2f}")
f"Ran out of cash to buy {symbol}. "
f"Cash: {cash_position} and limit_price: {limit_price:.2f}"
)

msg = "\nSubmitted buy orders:"
for order in buy_orders:
msg += f"\n{order}"
if buy_orders:
self.strategy.logger.info(msg)
self.strategy.log_message(msg, broadcast=True)
self.strategy.logger.info(f"Submitted buy order: {order}")

def calculate_limit_price(self, *, last_price: Decimal, side: str) -> Decimal:
if side == "sell":
Expand All @@ -398,26 +396,23 @@ def place_order(self, *, symbol: str, quantity: Decimal, limit_price: Decimal, s
quantity=quantity,
side=side
)
return self.strategy.submit_order(order)

self.strategy.submit_order(order)
return order

def _check_if_rebalance_needed(self, drift_df: pd.DataFrame) -> bool:
# Check if the absolute value of any drift is greater than the threshold
rebalance_needed = False
messages = ["\nDriftRebalancer summary:"]
for index, row in drift_df.iterrows():
msg = (
f"\nSymbol: {row['symbol']} current_weight: {row['current_weight']:.2%} "
f"Symbol: {row['symbol']} current_weight: {row['current_weight']:.2%} "
f"target_weight: {row['target_weight']:.2%} drift: {row['drift']:.2%}"
)
if abs(row["drift"]) > self.drift_threshold:
rebalance_needed = True
msg += (
f" Drift exceeds threshold."
)
messages.append(msg)

joined_messages = "".join(messages)
self.strategy.logger.info(joined_messages)
self.strategy.log_message(joined_messages, broadcast=True)
self.strategy.logger.info(msg)

return rebalance_needed
21 changes: 6 additions & 15 deletions lumibot/example_strategies/drift_rebalancer.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def initialize(self, parameters: Any = None) -> None:
self.fill_sleeptime = self.parameters.get("fill_sleeptime", 15)
self.target_weights = {k: Decimal(v) for k, v in self.parameters["target_weights"].items()}
self.shorting = self.parameters.get("shorting", False)
self.verbose = self.parameters.get("verbose", False)
self.drift_df = pd.DataFrame()
self.drift_rebalancer_logic = DriftRebalancerLogic(
strategy=self,
Expand All @@ -108,9 +109,7 @@ def initialize(self, parameters: Any = None) -> None:
# noinspection PyAttributeOutsideInit
def on_trading_iteration(self) -> None:
dt = self.get_datetime()
msg = f"{dt} on_trading_iteration called"
self.logger.info(msg)
self.log_message(msg, broadcast=True)
self.logger.info(f"{dt} on_trading_iteration called")
self.cancel_open_orders()

if self.cash < 0:
Expand All @@ -120,22 +119,14 @@ def on_trading_iteration(self) -> None:
)

self.drift_df = self.drift_rebalancer_logic.calculate(target_weights=self.target_weights)
rebalance_needed = self.drift_rebalancer_logic.rebalance(drift_df=self.drift_df)

if rebalance_needed:
msg = f"Rebalancing portfolio."
self.logger.info(msg)
self.log_message(msg, broadcast=True)
self.drift_rebalancer_logic.rebalance(drift_df=self.drift_df)

def on_abrupt_closing(self):
dt = self.get_datetime()
self.logger.info(f"{dt} on_abrupt_closing called")
self.log_message("On abrupt closing called.", broadcast=True)
self.cancel_open_orders()
self.logger.error(f"on_abrupt_closing called")

def on_bot_crash(self, error):
dt = self.get_datetime()
self.logger.info(f"{dt} on_bot_crash called")
self.log_message(f"Bot crashed with error: {error}", broadcast=True)
self.cancel_open_orders()
self.logger.error(f"on_bot_crash called with error: {error}")


0 comments on commit 6958933

Please sign in to comment.