lumibot 4.2.4__py3-none-any.whl → 4.2.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of lumibot might be problematic. Click here for more details.
- lumibot/strategies/_strategy.py +18 -4
- lumibot/strategies/strategy_executor.py +1 -3
- lumibot/tools/thetadata_helper.py +8 -2
- {lumibot-4.2.4.dist-info → lumibot-4.2.5.dist-info}/METADATA +1 -1
- {lumibot-4.2.4.dist-info → lumibot-4.2.5.dist-info}/RECORD +9 -9
- tests/test_backtesting_datetime_normalization.py +4 -0
- {lumibot-4.2.4.dist-info → lumibot-4.2.5.dist-info}/WHEEL +0 -0
- {lumibot-4.2.4.dist-info → lumibot-4.2.5.dist-info}/licenses/LICENSE +0 -0
- {lumibot-4.2.4.dist-info → lumibot-4.2.5.dist-info}/top_level.txt +0 -0
lumibot/strategies/_strategy.py
CHANGED
|
@@ -124,6 +124,17 @@ class Vars:
|
|
|
124
124
|
|
|
125
125
|
|
|
126
126
|
class _Strategy:
|
|
127
|
+
@staticmethod
|
|
128
|
+
def _normalize_backtest_datetime(value):
|
|
129
|
+
"""Convert backtest boundary datetimes to the LumiBot default timezone."""
|
|
130
|
+
if value is None:
|
|
131
|
+
return None
|
|
132
|
+
aware = to_datetime_aware(value)
|
|
133
|
+
tzinfo = getattr(aware, "tzinfo", None)
|
|
134
|
+
if tzinfo is not None and tzinfo != LUMIBOT_DEFAULT_PYTZ:
|
|
135
|
+
return aware.astimezone(LUMIBOT_DEFAULT_PYTZ)
|
|
136
|
+
return aware
|
|
137
|
+
|
|
127
138
|
@property
|
|
128
139
|
def is_backtesting(self) -> bool:
|
|
129
140
|
"""Boolean flag indicating whether the strategy is running in backtesting mode."""
|
|
@@ -1389,8 +1400,8 @@ class _Strategy:
|
|
|
1389
1400
|
raise ValueError(f"`optionsource_class` must be a class. You passed in {optionsource_class}")
|
|
1390
1401
|
|
|
1391
1402
|
try:
|
|
1392
|
-
backtesting_start =
|
|
1393
|
-
backtesting_end =
|
|
1403
|
+
backtesting_start = self._normalize_backtest_datetime(backtesting_start)
|
|
1404
|
+
backtesting_end = self._normalize_backtest_datetime(backtesting_end)
|
|
1394
1405
|
except AttributeError:
|
|
1395
1406
|
get_logger(__name__).error(
|
|
1396
1407
|
"`backtesting_start` and `backtesting_end` must be datetime objects. \n"
|
|
@@ -1399,6 +1410,9 @@ class _Strategy:
|
|
|
1399
1410
|
)
|
|
1400
1411
|
return None
|
|
1401
1412
|
|
|
1413
|
+
get_logger(__name__).info("Backtest start = %s", backtesting_start)
|
|
1414
|
+
get_logger(__name__).info("Backtest end = %s", backtesting_end)
|
|
1415
|
+
|
|
1402
1416
|
self.verify_backtest_inputs(backtesting_start, backtesting_end)
|
|
1403
1417
|
|
|
1404
1418
|
if not self.IS_BACKTESTABLE:
|
|
@@ -1628,8 +1642,8 @@ class _Strategy:
|
|
|
1628
1642
|
if not isinstance(backtesting_end, datetime.datetime):
|
|
1629
1643
|
raise ValueError(f"`backtesting_end` must be a datetime object. You passed in {backtesting_end}")
|
|
1630
1644
|
|
|
1631
|
-
start_dt =
|
|
1632
|
-
end_dt =
|
|
1645
|
+
start_dt = cls._normalize_backtest_datetime(backtesting_start)
|
|
1646
|
+
end_dt = cls._normalize_backtest_datetime(backtesting_end)
|
|
1633
1647
|
|
|
1634
1648
|
# Check that backtesting end is after backtesting start
|
|
1635
1649
|
if end_dt <= start_dt:
|
|
@@ -13,8 +13,6 @@ import pandas_market_calendars as mcal
|
|
|
13
13
|
from apscheduler.jobstores.memory import MemoryJobStore
|
|
14
14
|
from apscheduler.schedulers.background import BackgroundScheduler
|
|
15
15
|
from apscheduler.triggers.cron import CronTrigger
|
|
16
|
-
from termcolor import colored
|
|
17
|
-
|
|
18
16
|
from lumibot.constants import LUMIBOT_DEFAULT_PYTZ
|
|
19
17
|
from lumibot.entities import Asset, Order
|
|
20
18
|
from lumibot.entities import Asset
|
|
@@ -1166,7 +1164,7 @@ class StrategyExecutor(Thread):
|
|
|
1166
1164
|
# For live trading, stop when market closes
|
|
1167
1165
|
return False
|
|
1168
1166
|
|
|
1169
|
-
self.strategy.
|
|
1167
|
+
self.strategy.logger.debug("Sleeping for %s seconds", strategy_sleeptime)
|
|
1170
1168
|
|
|
1171
1169
|
# Run process orders at the market close time first (if not continuous market)
|
|
1172
1170
|
if not is_continuous_market:
|
|
@@ -311,7 +311,13 @@ def get_price_data(
|
|
|
311
311
|
)
|
|
312
312
|
|
|
313
313
|
if cache_file.exists():
|
|
314
|
-
logger.
|
|
314
|
+
logger.debug(
|
|
315
|
+
"\nLoading '%s' pricing data for %s / %s with '%s' timespan from cache file...",
|
|
316
|
+
datastyle,
|
|
317
|
+
asset,
|
|
318
|
+
quote_asset,
|
|
319
|
+
timespan,
|
|
320
|
+
)
|
|
315
321
|
df_cached = load_cache(cache_file)
|
|
316
322
|
if df_cached is not None and not df_cached.empty:
|
|
317
323
|
df_all = df_cached.copy() # Make a copy so we can check the original later for differences
|
|
@@ -372,7 +378,7 @@ def get_price_data(
|
|
|
372
378
|
)
|
|
373
379
|
if not missing_dates:
|
|
374
380
|
if df_all is not None and not df_all.empty:
|
|
375
|
-
logger.
|
|
381
|
+
logger.debug("ThetaData cache HIT for %s %s %s (%d rows).", asset, timespan, datastyle, len(df_all))
|
|
376
382
|
# DEBUG-LOG: Cache hit
|
|
377
383
|
logger.debug(
|
|
378
384
|
"[THETA][DEBUG][CACHE][HIT] asset=%s timespan=%s datastyle=%s rows=%d start=%s end=%s",
|
|
@@ -104,10 +104,10 @@ lumibot/example_strategies/test_broker_functions.py,sha256=wnVS-M_OtzMgaXVBgshVE
|
|
|
104
104
|
lumibot/resources/ThetaTerminal.jar,sha256=K6GeeFcN8-gvyL2x5iq5pzD79KfPJvMK8iiezi3TmNQ,11834389
|
|
105
105
|
lumibot/resources/conf.yaml,sha256=rjB9-10JP7saZ_edjX5bQDGfuc3amOQTUUUr-UiMpNA,597
|
|
106
106
|
lumibot/strategies/__init__.py,sha256=jEZ95K5hG0f595EXYKWwL2_UsnWWk5Pug361PK2My2E,79
|
|
107
|
-
lumibot/strategies/_strategy.py,sha256=
|
|
107
|
+
lumibot/strategies/_strategy.py,sha256=wWx2te98kwMTuusioKR24KsKW8Djs3yhOb2nNmvgbiU,111467
|
|
108
108
|
lumibot/strategies/session_manager.py,sha256=Nze6UYNSPlCsf-tyHvtFqUeL44WSNHjwsKrIepvsyCY,12956
|
|
109
109
|
lumibot/strategies/strategy.py,sha256=toPeL5oIVWmCxBNcfXqIuTCF_EeCfIVj425PrSYImCo,170021
|
|
110
|
-
lumibot/strategies/strategy_executor.py,sha256=
|
|
110
|
+
lumibot/strategies/strategy_executor.py,sha256=AnmXlKD2eMgKXs3TrD1u8T_Zsn_8GnG5KRcM_Pq-JBQ,70749
|
|
111
111
|
lumibot/tools/__init__.py,sha256=oRRoK2NBkfnc0kueAfY0HrWVKgzRBO1hlglVMR4jr5M,1501
|
|
112
112
|
lumibot/tools/alpaca_helpers.py,sha256=nhBS-sv28lZfIQ85szC9El8VHLrCw5a5KbsGOOEjm6w,3147
|
|
113
113
|
lumibot/tools/backtest_cache.py,sha256=A-Juzu0swZI_FP4U7cd7ruYTgJYgV8BPf_WJDI-NtrM,9556
|
|
@@ -132,7 +132,7 @@ lumibot/tools/polygon_helper_async.py,sha256=YHDXa9kmkkn8jh7hToY6GP5etyXS9Tj-uky
|
|
|
132
132
|
lumibot/tools/polygon_helper_polars_optimized.py,sha256=NaIZ-5Av-G2McPEKHyJ-x65W72W_Agnz4lRgvXfQp8c,30415
|
|
133
133
|
lumibot/tools/projectx_helpers.py,sha256=EIemLfbG923T_RBV_i6s6A9xgs7dt0et0oCnhFwdWfA,58299
|
|
134
134
|
lumibot/tools/schwab_helper.py,sha256=CXnYhgsXOIb5MgmIYOp86aLxsBF9oeVrMGrjwl_GEv0,11768
|
|
135
|
-
lumibot/tools/thetadata_helper.py,sha256
|
|
135
|
+
lumibot/tools/thetadata_helper.py,sha256=Guutp_2QAZe22_r6pftCojpTb3DpDp4Ul_szf6N7X1I,80152
|
|
136
136
|
lumibot/tools/types.py,sha256=x-aQBeC6ZTN2-pUyxyo69Q0j5e0c_swdfe06kfrWSVc,1978
|
|
137
137
|
lumibot/tools/yahoo_helper.py,sha256=htcKKkuktatIckVKfLc_ms0X75mXColysQhrZW244z8,19497
|
|
138
138
|
lumibot/tools/yahoo_helper_polars_optimized.py,sha256=g9xBN-ReHSW4Aj9EMU_OncBXVS1HpfL8LTHit9ZxFY4,7417
|
|
@@ -142,7 +142,7 @@ lumibot/traders/trader.py,sha256=KMif3WoZtnSxA0BzoK3kvkTITNELrDFIortx1BYBv8s,967
|
|
|
142
142
|
lumibot/trading_builtins/__init__.py,sha256=vH2QL5zLjL3slfEV1YW-BvQHtEYLCFkIWTZDfh3y8LE,87
|
|
143
143
|
lumibot/trading_builtins/custom_stream.py,sha256=8_XiPT0JzyXrgnXCXoovGGUrWEfnG4ohIYMPfB_Nook,5264
|
|
144
144
|
lumibot/trading_builtins/safe_list.py,sha256=IIjZOHSiZYK25A4WBts0oJaZNOJDsjZL65MOSHhE3Ig,1975
|
|
145
|
-
lumibot-4.2.
|
|
145
|
+
lumibot-4.2.5.dist-info/licenses/LICENSE,sha256=fYhGIyxjyNXACgpNQS3xxpxDOaVOWRVxZMCRbsDv8k0,35130
|
|
146
146
|
tests/__init__.py,sha256=3-VoT-nAuqMfwufd4ceN6fXaHl_zCfDCSXJOTp1ywYQ,393
|
|
147
147
|
tests/conftest.py,sha256=UBw_2fx7r6TZPKus2b1Qxrzmd4bg8EEBnX1vCHUuSVA,3311
|
|
148
148
|
tests/fixtures.py,sha256=wOHQsh1SGHnXe_PGi6kDWI30CS_Righi7Ig7vwSEKT4,9082
|
|
@@ -163,7 +163,7 @@ tests/test_backtesting_broker_await_close.py,sha256=WbehY7E4Qet3_Mo7lpfgjmhtI9pn
|
|
|
163
163
|
tests/test_backtesting_broker_time_advance.py,sha256=FCv0nKG8BQlEjNft7kmQYm9M2CsLIZ0b7mWCllOHQxc,6378
|
|
164
164
|
tests/test_backtesting_crypto_cash_unit.py,sha256=4EO9jVajdZNV0M7zSyp4gpR_msZFoM4x5tb-6g-mHO8,11399
|
|
165
165
|
tests/test_backtesting_data_source_env.py,sha256=ZzpF42-tMc8qqETuy_nf43UsSZMbHtS_ivH93ZqV5P0,12460
|
|
166
|
-
tests/test_backtesting_datetime_normalization.py,sha256=
|
|
166
|
+
tests/test_backtesting_datetime_normalization.py,sha256=n1ObwObTI_V4uQOQw_WIii7Ph_OgPZYIZGbx5Jv_19U,3245
|
|
167
167
|
tests/test_backtesting_flow_control.py,sha256=pBqW-fa-HnZq0apUBltalGMM-vNJ_2A5W2SoJzMK8Mg,7208
|
|
168
168
|
tests/test_backtesting_multileg_unit.py,sha256=h1DPfVuYXXx-uq6KtUjr6_nasZuXPm_5gFat1XxCKIo,6456
|
|
169
169
|
tests/test_backtesting_quiet_logs_complete.py,sha256=x-GfOiqkiUu8pYKCzB0UUacn13Nx_cPRth7_jmPY2Y8,14155
|
|
@@ -281,7 +281,7 @@ tests/backtest/test_thetadata.py,sha256=xWYfC9C4EhbMDb29qyZWHO3sSWaLIPzzvcMbHCt5
|
|
|
281
281
|
tests/backtest/test_thetadata_comprehensive.py,sha256=-gN3xLJcJtlB-k4vlaK82DCZDGDmr0LNZZDzn-aN3l4,26120
|
|
282
282
|
tests/backtest/test_thetadata_vs_polygon.py,sha256=dZqsrOx3u3cz-1onIO6o5BDRjI1ey7U9vIkZupfXoig,22831
|
|
283
283
|
tests/backtest/test_yahoo.py,sha256=2FguUTUMC9_A20eqxnZ17rN3tT9n6hyvJHaL98QKpqY,3443
|
|
284
|
-
lumibot-4.2.
|
|
285
|
-
lumibot-4.2.
|
|
286
|
-
lumibot-4.2.
|
|
287
|
-
lumibot-4.2.
|
|
284
|
+
lumibot-4.2.5.dist-info/METADATA,sha256=lK1f_O0TcWv79IUVPehgpO2s_dQE1jrsj69_LCqeKM8,12092
|
|
285
|
+
lumibot-4.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
286
|
+
lumibot-4.2.5.dist-info/top_level.txt,sha256=otUnUjDFVASauEDiTiAzNgMyqQ1B6jjS3QqqP-WSx38,14
|
|
287
|
+
lumibot-4.2.5.dist-info/RECORD,,
|
|
@@ -3,6 +3,7 @@ from unittest.mock import patch
|
|
|
3
3
|
|
|
4
4
|
import pytest
|
|
5
5
|
|
|
6
|
+
from lumibot.constants import LUMIBOT_DEFAULT_PYTZ
|
|
6
7
|
from lumibot.strategies import Strategy
|
|
7
8
|
from lumibot.strategies._strategy import _Strategy
|
|
8
9
|
|
|
@@ -88,3 +89,6 @@ def test_run_backtest_normalizes_mixed_timezones():
|
|
|
88
89
|
|
|
89
90
|
assert "start" in captured and captured["start"].tzinfo is not None
|
|
90
91
|
assert "end" in captured and captured["end"].tzinfo is not None
|
|
92
|
+
assert captured["start"].tzinfo.zone == LUMIBOT_DEFAULT_PYTZ.zone
|
|
93
|
+
assert captured["end"].tzinfo.zone == LUMIBOT_DEFAULT_PYTZ.zone
|
|
94
|
+
assert captured["start"].tzinfo.zone == captured["end"].tzinfo.zone
|
|
File without changes
|
|
File without changes
|
|
File without changes
|