Skip to content

Commit

Permalink
quiet_logs now works. for realz. with tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
brettelliot committed Oct 25, 2024
1 parent dd4732f commit 0f7e14c
Show file tree
Hide file tree
Showing 15 changed files with 162 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ todos.txt
test_bot.py
.vscode
.coverage*
*secret*/**.env
.env
lumi_tradier
lumiwealth_tradier
ThetaTerminal.jar
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ Our blog has lots of example strategies and shows you how to run a bot using Lum

**https://lumiwealth.com/blog/**

## Run a backtest

To run a backtest, you can use the following code snippet:

```bash
python -m lumibot.example_strategies.stock_buy_and_hold
```

## Run an Example Strategy

We made a small example strategy to show you how to use Lumibot in this GitHub repository: [Example Algorithm GitHub](https://github.com/Lumiwealth-Strategies/stock_example_algo)
Expand Down
1 change: 0 additions & 1 deletion lumibot/backtesting/backtesting_broker.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from lumibot.trading_builtins import CustomStream

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


class BacktestingBroker(Broker):
Expand Down
1 change: 0 additions & 1 deletion lumibot/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

# Configure logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


def find_and_load_dotenv(base_dir) -> bool:
Expand Down
1 change: 0 additions & 1 deletion lumibot/data_sources/yahoo_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from lumibot.tools import YahooHelper

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


class YahooData(DataSourceBacktesting):
Expand Down
34 changes: 33 additions & 1 deletion lumibot/example_strategies/lifecycle_logger.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import logging
import datetime

from lumibot.strategies.strategy import Strategy

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


class LifecycleLogger(Strategy):
Expand Down Expand Up @@ -37,3 +37,35 @@ def after_market_closes(self):
dt = self.get_datetime()
logger.info(f"{dt} after_market_closes called")


if __name__ == "__main__":
IS_BACKTESTING = True

if IS_BACKTESTING:
from lumibot.backtesting import YahooDataBacktesting

# Backtest this strategy
backtesting_start = datetime.datetime(2023, 1, 1)
backtesting_end = datetime.datetime(2024, 9, 1)

results = LifecycleLogger.backtest(
YahooDataBacktesting,
backtesting_start,
backtesting_end,
benchmark_asset="SPY",
# show_progress_bar=False,
# quiet_logs=False,
)

# Print the results
print(results)
else:
from lumibot.credentials import ALPACA_CONFIG
from lumibot.brokers import Alpaca
from lumibot.traders import Trader

trader = Trader()
broker = Alpaca(ALPACA_CONFIG)
strategy = LifecycleLogger(broker=broker)
trader.add_strategy(strategy)
strategy_executors = trader.run_all()
3 changes: 0 additions & 3 deletions lumibot/strategies/_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,9 +1013,6 @@ def run_backtest(
if not hasattr(self, "logger") or self.logger is None:
self.logger = CustomLoggerAdapter(logger, {'strategy_name': self._name})

# Print start message
print(f"Starting backtest for {datasource_class.__name__}...")

# If show_plot is None, then set it to True
if show_plot is None:
show_plot = SHOW_PLOT
Expand Down
1 change: 0 additions & 1 deletion lumibot/tools/indicators.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from .yahoo_helper import YahooHelper as yh

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


def total_return(_df):
Expand Down
6 changes: 3 additions & 3 deletions lumibot/traders/trader.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
# Overloading time.sleep to warn users against using it

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


class Trader:
Expand Down Expand Up @@ -142,6 +141,7 @@ def run_all(
result = self._collect_analysis()

if self.is_backtest_broker:
logger.setLevel(logging.INFO)
logger.info("Backtesting finished")
strat.backtest_analysis(
logdir=self.logdir,
Expand Down Expand Up @@ -189,8 +189,8 @@ def _set_logger(self):

if self.debug:
logger.setLevel(logging.DEBUG)
elif self.is_backtest_broker:
logger.setLevel(logging.INFO)
elif self.quiet_logs:
logger.setLevel(logging.ERROR)
for handler in logger.handlers:
if handler.__class__.__name__ == "StreamHandler":
handler.setLevel(logging.ERROR)
Expand Down
1 change: 0 additions & 1 deletion tests/backtest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from lumibot.backtesting import PolygonDataBacktesting

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


@pytest.fixture
Expand Down
2 changes: 1 addition & 1 deletion tests/backtest/test_example_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def test_stock_bracket(self):
show_plot=False,
show_tearsheet=False,
save_tearsheet=False,
polygon_api_key=POLYGON_API_KEY,
show_indicators=False,
)
assert results
assert isinstance(strat_obj, StockBracket)
Expand Down
1 change: 0 additions & 1 deletion tests/backtest/test_pandas_backtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@


logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


class TestPandasBacktest:
Expand Down
1 change: 0 additions & 1 deletion tests/backtest/test_passing_trader_into_backtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from tests.backtest.fixtures import pandas_data_fixture

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


class TestPassingTraderIntoBacktest:
Expand Down
3 changes: 2 additions & 1 deletion tests/backtest/test_polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import pandas_market_calendars as mcal


from tests.backtest.fixtures import polygon_data_backtesting
import pytz
from lumibot.backtesting import BacktestingBroker, PolygonDataBacktesting
Expand All @@ -18,7 +19,7 @@

# Global parameters
# API Key for testing Polygon.io
POLYGON_API_KEY = os.environ.get("POLYGON_API_KEY")
from lumibot.credentials import POLYGON_API_KEY


class PolygonBacktestStrat(Strategy):
Expand Down
114 changes: 114 additions & 0 deletions tests/test_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import datetime
import logging

from lumibot.example_strategies.lifecycle_logger import LifecycleLogger
from lumibot.backtesting import YahooDataBacktesting


class TestLogging:

def test_logging(self, caplog):
caplog.set_level(logging.INFO)
logger = logging.getLogger()
logger.info("This is an info message")
assert "This is an info message" in caplog.text

def test_backtest_produces_no_logs_by_default(self, caplog):
caplog.set_level(logging.INFO)
backtesting_start = datetime.datetime(2023, 1, 2)
backtesting_end = datetime.datetime(2023, 1, 4)

LifecycleLogger.backtest(
YahooDataBacktesting,
backtesting_start,
backtesting_end,
parameters={"sleeptime": "1D", "market": "NYSE"},
show_plot=False,
save_tearsheet=False,
show_tearsheet=False,
show_indicators=False,
save_logfile=False,
)
# count that this contains 3 new lines. Its an easy proxy for the number of log messages and avoids
# the issue where the datetime is always gonna be different.
assert caplog.text.count("\n") == 3
assert "Starting backtest...\n" in caplog.text
assert "Backtesting starting...\n" in caplog.text
assert "Backtesting finished\n" in caplog.text

def test_run_backtest_produces_no_logs_by_default(self, caplog):
caplog.set_level(logging.INFO)
backtesting_start = datetime.datetime(2023, 1, 2)
backtesting_end = datetime.datetime(2023, 1, 4)

LifecycleLogger.run_backtest(
YahooDataBacktesting,
backtesting_start,
backtesting_end,
parameters={"sleeptime": "1D", "market": "NYSE"},
show_plot=False,
save_tearsheet=False,
show_tearsheet=False,
show_indicators=False,
save_logfile=False,
)
# count that this contains 3 new lines. Its an easy proxy for the number of log messages and avoids
# the issue where the datetime is always gonna be different.
assert caplog.text.count("\n") == 3
assert "Starting backtest...\n" in caplog.text
assert "Backtesting starting...\n" in caplog.text
assert "Backtesting finished\n" in caplog.text

def test_backtest_produces_no_logs_when_quiet_logs_is_true(self, caplog):
caplog.set_level(logging.INFO)
backtesting_start = datetime.datetime(2023, 1, 2)
backtesting_end = datetime.datetime(2023, 1, 4)

LifecycleLogger.backtest(
YahooDataBacktesting,
backtesting_start,
backtesting_end,
parameters={"sleeptime": "1D", "market": "NYSE"},
show_plot=False,
save_tearsheet=False,
show_tearsheet=False,
show_indicators=False,
save_logfile=False,
show_progress_bar=True,
quiet_logs=True,
)
# count that this contains 3 new lines. Its an easy proxy for the number of log messages and avoids
# the issue where the datetime is always gonna be different.
assert caplog.text.count("\n") == 3
assert "Starting backtest...\n" in caplog.text
assert "Backtesting starting...\n" in caplog.text
assert "Backtesting finished\n" in caplog.text

def test_backtest_produces_logs_when_quiet_logs_is_false(self, caplog):
caplog.set_level(logging.INFO)
backtesting_start = datetime.datetime(2023, 1, 2)
backtesting_end = datetime.datetime(2023, 1, 4)

LifecycleLogger.backtest(
YahooDataBacktesting,
backtesting_start,
backtesting_end,
parameters={"sleeptime": "1D", "market": "NYSE"},
show_plot=False,
save_tearsheet=False,
show_tearsheet=False,
show_indicators=False,
save_logfile=False,
show_progress_bar=False,
quiet_logs=False,
)

assert caplog.text.count("\n") == 9
assert "Starting backtest...\n" in caplog.text
assert "Backtesting starting...\n" in caplog.text
assert "before_market_opens called\n" in caplog.text
assert "before_starting_trading called\n" in caplog.text
assert "on_trading_iteration called\n" in caplog.text
assert "before_market_closes called\n" in caplog.text
assert "after_market_closes called\n" in caplog.text
assert "Backtesting finished\n" in caplog.text

0 comments on commit 0f7e14c

Please sign in to comment.