lumibot 4.2.4__tar.gz → 4.2.6__tar.gz
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-4.2.4/lumibot.egg-info → lumibot-4.2.6}/PKG-INFO +2 -2
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/databento_backtesting_pandas.py +3 -3
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/thetadata_backtesting_pandas.py +1 -1
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/components/options_helper.py +86 -23
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/strategies/_strategy.py +24 -4
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/strategies/strategy_executor.py +1 -3
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/ccxt_data_store.py +1 -1
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/databento_helper.py +3 -3
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/thetadata_helper.py +255 -59
- {lumibot-4.2.4 → lumibot-4.2.6/lumibot.egg-info}/PKG-INFO +2 -2
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot.egg-info/SOURCES.txt +1 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot.egg-info/requires.txt +1 -1
- {lumibot-4.2.4 → lumibot-4.2.6}/setup.py +2 -2
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_backtesting_datetime_normalization.py +4 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_options_helper.py +45 -3
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_projectx_timestep_alias.py +1 -2
- lumibot-4.2.6/tests/test_strategy_price_guard.py +50 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_thetadata_helper.py +187 -63
- {lumibot-4.2.4 → lumibot-4.2.6}/LICENSE +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/MANIFEST.in +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/README.md +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/alpaca_backtesting.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/alpha_vantage_backtesting.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/backtesting_broker.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/ccxt_backtesting.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/databento_backtesting.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/databento_backtesting_polars.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/fix_debug.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/interactive_brokers_rest_backtesting.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/pandas_backtesting.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/polygon_backtesting.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/thetadata_backtesting.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/backtesting/yahoo_backtesting.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/brokers/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/brokers/alpaca.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/brokers/bitunix.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/brokers/broker.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/brokers/ccxt.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/brokers/example_broker.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/brokers/interactive_brokers.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/brokers/interactive_brokers_rest.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/brokers/projectx.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/brokers/schwab.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/brokers/tradier.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/brokers/tradovate.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/components/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/components/configs_helper.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/components/drift_rebalancer_logic.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/components/grok_helper.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/components/perplexity_helper.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/components/quiver_helper.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/components/vix_helper.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/constants.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/credentials.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/alpaca_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/alpha_vantage_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/bitunix_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/ccxt_backtesting_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/ccxt_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/data_source.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/data_source_backtesting.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/databento_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/databento_data_pandas.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/databento_data_polars.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/example_broker_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/exceptions.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/interactive_brokers_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/interactive_brokers_rest_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/pandas_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/polars_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/polars_mixin.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/polygon_data_polars.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/projectx_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/schwab_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/tradier_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/tradovate_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/yahoo_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/data_sources/yahoo_data_polars.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/entities/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/entities/asset.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/entities/bar.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/entities/bars.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/entities/chains.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/entities/data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/entities/data_polars.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/entities/dataline.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/entities/order.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/entities/position.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/entities/quote.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/entities/trading_fee.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/bitunix_futures_example.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/ccxt_backtesting_example.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/classic_60_40.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/classic_60_40_config.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/crypto_50_50.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/crypto_50_50_config.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/crypto_important_functions.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/drift_rebalancer.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/forex_hold_to_expiry.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/futures_hold_to_expiry.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/lifecycle_logger.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/options_hold_to_expiry.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/schedule_function.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/simple_start_single_file.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/stock_bracket.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/stock_buy_and_hold.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/stock_diversified_leverage.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/stock_limit_and_trailing_stops.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/stock_momentum.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/stock_oco.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/strangle.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/example_strategies/test_broker_functions.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/resources/ThetaTerminal.jar +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/resources/conf.yaml +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/strategies/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/strategies/session_manager.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/strategies/strategy.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/alpaca_helpers.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/backtest_cache.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/bitunix_helpers.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/black_scholes.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/databento_helper_polars.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/debugers.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/decorators.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/futures_roll.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/futures_symbols.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/helpers.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/indicators.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/lumibot_logger.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/lumibot_time.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/pandas.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/polars_utils.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/polygon_helper.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/polygon_helper_async.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/polygon_helper_polars_optimized.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/projectx_helpers.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/schwab_helper.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/types.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/yahoo_helper.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/tools/yahoo_helper_polars_optimized.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/traders/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/traders/debug_log_trader.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/traders/trader.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/trading_builtins/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/trading_builtins/custom_stream.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot/trading_builtins/safe_list.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot.egg-info/dependency_links.txt +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/lumibot.egg-info/top_level.txt +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/pyproject.toml +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/setup.cfg +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/__init__.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/conftest.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/performance_tracker.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/profile_thetadata_vs_polygon.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_accuracy_verification.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_backtesting_broker_processing.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_buy_hold_quiet_logs_full_run.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_crypto_cash_regressions.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_daily_data_timestamp_comparison.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_databento.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_databento_comprehensive_trading.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_databento_parity.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_debug_avg_fill_price.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_dividends.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_example_strategies.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_failing_backtest.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_futures_edge_cases.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_futures_single_trade.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_futures_ultra_simple.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_index_data_verification.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_multileg_backtest.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_pandas_backtest.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_passing_trader_into_backtest.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_polars_lru_eviction.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_polygon.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_strategy_executor.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_thetadata.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_thetadata_comprehensive.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_thetadata_vs_polygon.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/backtest/test_yahoo.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/conftest.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/fixtures.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_alpaca.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_alpaca_auth_fix.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_alpaca_backtesting.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_alpaca_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_alpaca_helpers.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_alpaca_multileg_fix.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_alpaca_oauth.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_apscheduler_warnings.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_asset.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_asset_auto_expiry.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_auto_market_inference.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_backtest_cache_manager.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_backtesting_broker.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_backtesting_broker_await_close.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_backtesting_broker_time_advance.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_backtesting_crypto_cash_unit.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_backtesting_data_source_env.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_backtesting_flow_control.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_backtesting_multileg_unit.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_backtesting_quiet_logs_complete.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_bars_aggregate_frequency_normalization.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_bars_aggregation_timeunits.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_bars_frequency_flex.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_botspot_handler.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_botspot_logger.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_broker_bitunix.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_broker_cleanup.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_broker_initialization.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_brokers_handle_crypto.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_cash.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_ccxt.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_ccxt_store.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_configs_helper.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_continuous_futures.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_continuous_futures_integration.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_continuous_futures_resolution.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_data_polars_parity.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_data_source.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_databento_asset_validation.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_databento_auto_expiry_integration.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_databento_backtesting.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_databento_backtesting_polars.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_databento_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_databento_helper.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_databento_live.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_databento_timezone_fixes.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_drift_rebalancer.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_futures_integration.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_futures_roll.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_get_historical_prices.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_helpers.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_indicator_subplots.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_integration_tests.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_interactive_brokers.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_live_trading_resilience.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_logger_env_vars.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_logging.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_lumibot_logger.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_market_infinite_loop_bug.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_mes_symbols.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_momentum.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_order.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_order_serialization.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_pandas_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_polars_resample.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_polygon_helper.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_position_serialization.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_projectx.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_projectx_bracket_helpers.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_projectx_bracket_lifecycle_unit.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_projectx_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_projectx_datetime_columns.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_projectx_datetime_index.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_projectx_helpers.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_projectx_lifecycle.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_projectx_lifecycle_unit.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_projectx_live_flow.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_projectx_url_mappings.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_quiet_logs_buy_and_hold.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_quiet_logs_comprehensive.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_quiet_logs_functionality.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_quiet_logs_requirements.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_session_manager.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_strategy_methods.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_thetadata_backwards_compat.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_thetadata_pandas_verification.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_tradier.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_tradier_data.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_tradingfee.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_tradovate.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_unified_logger.py +0 -0
- {lumibot-4.2.4 → lumibot-4.2.6}/tests/test_vix_helper.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lumibot
|
|
3
|
-
Version: 4.2.
|
|
3
|
+
Version: 4.2.6
|
|
4
4
|
Summary: Backtesting and Trading Library, Made by Lumiwealth
|
|
5
5
|
Home-page: https://github.com/Lumiwealth/lumibot
|
|
6
6
|
Author: Robert Grzesik
|
|
@@ -51,7 +51,7 @@ Requires-Dist: schwab-py>=1.5.0
|
|
|
51
51
|
Requires-Dist: Flask>=2.3
|
|
52
52
|
Requires-Dist: free-proxy
|
|
53
53
|
Requires-Dist: requests-oauthlib
|
|
54
|
-
Requires-Dist: boto3>=1.
|
|
54
|
+
Requires-Dist: boto3>=1.40.64
|
|
55
55
|
Dynamic: author
|
|
56
56
|
Dynamic: author-email
|
|
57
57
|
Dynamic: classifier
|
|
@@ -454,9 +454,9 @@ class DataBentoDataBacktestingPandas(PandasData):
|
|
|
454
454
|
filtered_df = df[df.index <= current_dt_aware]
|
|
455
455
|
|
|
456
456
|
if not filtered_df.empty:
|
|
457
|
-
|
|
458
|
-
if not
|
|
459
|
-
price = float(
|
|
457
|
+
valid_closes = filtered_df['close'].dropna()
|
|
458
|
+
if not valid_closes.empty:
|
|
459
|
+
price = float(valid_closes.iloc[-1])
|
|
460
460
|
# OPTIMIZATION: Cache the result
|
|
461
461
|
self._last_price_cache[cache_key] = price
|
|
462
462
|
return price
|
|
@@ -771,7 +771,7 @@ class ThetaDataBacktestingPandas(PandasData):
|
|
|
771
771
|
quote_columns = ['bid', 'ask', 'bid_size', 'ask_size', 'bid_condition', 'ask_condition', 'bid_exchange', 'ask_exchange']
|
|
772
772
|
existing_quote_cols = [col for col in quote_columns if col in df.columns]
|
|
773
773
|
if existing_quote_cols:
|
|
774
|
-
df[existing_quote_cols] = df[existing_quote_cols].
|
|
774
|
+
df[existing_quote_cols] = df[existing_quote_cols].ffill()
|
|
775
775
|
|
|
776
776
|
# Log how much forward filling occurred
|
|
777
777
|
if 'bid' in df.columns and 'ask' in df.columns:
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from datetime import date, datetime, timedelta
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
import math
|
|
3
5
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
4
6
|
import warnings
|
|
5
7
|
|
|
@@ -23,6 +25,7 @@ class OptionMarketEvaluation:
|
|
|
23
25
|
sell_price: Optional[float]
|
|
24
26
|
used_last_price_fallback: bool
|
|
25
27
|
max_spread_pct: Optional[float]
|
|
28
|
+
data_quality_flags: List[str]
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
class OptionsHelper:
|
|
@@ -58,6 +61,54 @@ class OptionsHelper:
|
|
|
58
61
|
self._liquidity_deprecation_warned = False
|
|
59
62
|
self.strategy.log_message("OptionsHelper initialized.", color="blue")
|
|
60
63
|
|
|
64
|
+
@staticmethod
|
|
65
|
+
def _coerce_price(value: Any, field_name: str, flags: List[str], notes: List[str]) -> Optional[float]:
|
|
66
|
+
"""Normalize quote values and record data quality issues."""
|
|
67
|
+
raw_value = value
|
|
68
|
+
|
|
69
|
+
if value is None:
|
|
70
|
+
flags.append(f"{field_name}_missing")
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
if isinstance(value, Decimal):
|
|
75
|
+
value = float(value)
|
|
76
|
+
else:
|
|
77
|
+
value = float(value) # type: ignore[arg-type]
|
|
78
|
+
except (TypeError, ValueError):
|
|
79
|
+
flags.append(f"{field_name}_non_numeric")
|
|
80
|
+
notes.append(f"{field_name} value {raw_value!r} is non-numeric; dropping.")
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
if math.isnan(value) or math.isinf(value):
|
|
84
|
+
flags.append(f"{field_name}_non_finite")
|
|
85
|
+
notes.append(f"{field_name} value {value!r} is not finite; dropping.")
|
|
86
|
+
return None
|
|
87
|
+
|
|
88
|
+
if value <= 0:
|
|
89
|
+
flags.append(f"{field_name}_non_positive")
|
|
90
|
+
notes.append(f"{field_name} value {value!r} is non-positive; dropping.")
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
return value
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def has_actionable_price(evaluation: Optional["OptionMarketEvaluation"]) -> bool:
|
|
97
|
+
"""Return True when the evaluation contains a usable buy price."""
|
|
98
|
+
if evaluation is None:
|
|
99
|
+
return False
|
|
100
|
+
|
|
101
|
+
price = evaluation.buy_price
|
|
102
|
+
if price is None:
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
price = float(price)
|
|
107
|
+
except (TypeError, ValueError):
|
|
108
|
+
return False
|
|
109
|
+
|
|
110
|
+
return math.isfinite(price) and price > 0 and not evaluation.spread_too_wide
|
|
111
|
+
|
|
61
112
|
# ============================================================
|
|
62
113
|
# Basic Utility Functions
|
|
63
114
|
# ============================================================
|
|
@@ -467,6 +518,9 @@ class OptionsHelper:
|
|
|
467
518
|
buy_price: Optional[float] = None
|
|
468
519
|
sell_price: Optional[float] = None
|
|
469
520
|
|
|
521
|
+
data_quality_flags: List[str] = []
|
|
522
|
+
sanitization_notes: List[str] = []
|
|
523
|
+
|
|
470
524
|
# Attempt to get quotes first
|
|
471
525
|
quote = None
|
|
472
526
|
try:
|
|
@@ -478,24 +532,20 @@ class OptionsHelper:
|
|
|
478
532
|
)
|
|
479
533
|
|
|
480
534
|
if quote and quote.bid is not None and quote.ask is not None:
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
ask = float(quote.ask)
|
|
484
|
-
except (TypeError, ValueError):
|
|
485
|
-
bid = quote.bid
|
|
486
|
-
ask = quote.ask
|
|
535
|
+
bid = self._coerce_price(quote.bid, "bid", data_quality_flags, sanitization_notes)
|
|
536
|
+
ask = self._coerce_price(quote.ask, "ask", data_quality_flags, sanitization_notes)
|
|
487
537
|
has_bid_ask = bid is not None and ask is not None
|
|
488
538
|
|
|
489
539
|
if has_bid_ask and bid is not None and ask is not None:
|
|
490
540
|
buy_price = ask
|
|
491
541
|
sell_price = bid
|
|
492
|
-
mid = (ask + bid) / 2
|
|
493
|
-
if mid
|
|
542
|
+
mid = (ask + bid) / 2
|
|
543
|
+
if not math.isfinite(mid) or mid <= 0:
|
|
544
|
+
spread_pct = None
|
|
545
|
+
else:
|
|
494
546
|
spread_pct = (ask - bid) / mid
|
|
495
547
|
if max_spread_pct is not None:
|
|
496
548
|
spread_too_wide = spread_pct > max_spread_pct
|
|
497
|
-
else:
|
|
498
|
-
spread_pct = None
|
|
499
549
|
else:
|
|
500
550
|
missing_bid_ask = True
|
|
501
551
|
|
|
@@ -510,6 +560,10 @@ class OptionsHelper:
|
|
|
510
560
|
|
|
511
561
|
if last_price is None:
|
|
512
562
|
missing_last_price = True
|
|
563
|
+
else:
|
|
564
|
+
last_price = self._coerce_price(last_price, "last_price", data_quality_flags, sanitization_notes)
|
|
565
|
+
if last_price is None:
|
|
566
|
+
missing_last_price = True
|
|
513
567
|
|
|
514
568
|
if not has_bid_ask and allow_fallback and last_price is not None:
|
|
515
569
|
buy_price = last_price
|
|
@@ -519,6 +573,14 @@ class OptionsHelper:
|
|
|
519
573
|
f"Using last-price fallback for {option_asset} due to missing bid/ask quotes.",
|
|
520
574
|
color="yellow",
|
|
521
575
|
)
|
|
576
|
+
elif not has_bid_ask and allow_fallback and last_price is None:
|
|
577
|
+
data_quality_flags.append("last_price_unusable")
|
|
578
|
+
|
|
579
|
+
if buy_price is not None and (not math.isfinite(buy_price) or buy_price <= 0):
|
|
580
|
+
sanitization_notes.append(f"buy_price {buy_price!r} is not actionable; clearing.")
|
|
581
|
+
data_quality_flags.append("buy_price_non_finite")
|
|
582
|
+
buy_price = None
|
|
583
|
+
sell_price = None
|
|
522
584
|
|
|
523
585
|
# Compose log message
|
|
524
586
|
spread_str = f"{spread_pct:.2%}" if spread_pct is not None else "None"
|
|
@@ -526,6 +588,12 @@ class OptionsHelper:
|
|
|
526
588
|
log_color = "red" if spread_too_wide else (
|
|
527
589
|
"yellow" if (missing_bid_ask or missing_last_price or used_last_price_fallback) else "blue"
|
|
528
590
|
)
|
|
591
|
+
if sanitization_notes:
|
|
592
|
+
note_summary = "; ".join(sanitization_notes)
|
|
593
|
+
self.strategy.log_message(
|
|
594
|
+
f"Option data sanitization for {option_asset}: {note_summary}",
|
|
595
|
+
color="yellow",
|
|
596
|
+
)
|
|
529
597
|
self.strategy.log_message(
|
|
530
598
|
(
|
|
531
599
|
f"Option market evaluation for {option_asset}: "
|
|
@@ -533,7 +601,8 @@ class OptionsHelper:
|
|
|
533
601
|
f"max_spread={max_spread_str}, missing_bid_ask={missing_bid_ask}, "
|
|
534
602
|
f"missing_last_price={missing_last_price}, spread_too_wide={spread_too_wide}, "
|
|
535
603
|
f"used_last_price_fallback={used_last_price_fallback}, "
|
|
536
|
-
f"buy_price={buy_price}, sell_price={sell_price}"
|
|
604
|
+
f"buy_price={buy_price}, sell_price={sell_price}, "
|
|
605
|
+
f"data_quality_flags={data_quality_flags}"
|
|
537
606
|
),
|
|
538
607
|
color=log_color,
|
|
539
608
|
)
|
|
@@ -551,6 +620,7 @@ class OptionsHelper:
|
|
|
551
620
|
sell_price=sell_price,
|
|
552
621
|
used_last_price_fallback=used_last_price_fallback,
|
|
553
622
|
max_spread_pct=max_spread_pct,
|
|
623
|
+
data_quality_flags=data_quality_flags,
|
|
554
624
|
)
|
|
555
625
|
|
|
556
626
|
def check_option_liquidity(self, option_asset: Asset, max_spread_pct: float) -> bool:
|
|
@@ -721,18 +791,11 @@ class OptionsHelper:
|
|
|
721
791
|
self.strategy.log_message(f"Cannot validate data without underlying symbol, returning {exp_date}", color="yellow")
|
|
722
792
|
return exp_date
|
|
723
793
|
|
|
724
|
-
# No future expirations with
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
if strikes and len(strikes) > 0:
|
|
730
|
-
self.strategy.log_message(
|
|
731
|
-
f"No valid expirations on or after {dt}; using latest available {exp_date} for {call_or_put_caps}.",
|
|
732
|
-
color="yellow",
|
|
733
|
-
)
|
|
734
|
-
return exp_date
|
|
735
|
-
|
|
794
|
+
# No future expirations with tradeable data; let the caller skip entries gracefully.
|
|
795
|
+
self.strategy.log_message(
|
|
796
|
+
f"No valid expirations on or after {dt} with tradeable data for {call_or_put_caps}; skipping.",
|
|
797
|
+
color="yellow",
|
|
798
|
+
)
|
|
736
799
|
return None
|
|
737
800
|
|
|
738
801
|
# ============================================================
|
|
@@ -124,6 +124,23 @@ class Vars:
|
|
|
124
124
|
|
|
125
125
|
|
|
126
126
|
class _Strategy:
|
|
127
|
+
@staticmethod
|
|
128
|
+
def _normalize_backtest_datetime(value):
|
|
129
|
+
"""Ensure backtest boundary datetimes are timezone-aware.
|
|
130
|
+
|
|
131
|
+
Naive datetimes are localized to the LumiBot default timezone; timezone-aware
|
|
132
|
+
inputs are returned unchanged so their original offsets are preserved.
|
|
133
|
+
"""
|
|
134
|
+
if value is None:
|
|
135
|
+
return None
|
|
136
|
+
if isinstance(value, datetime.datetime):
|
|
137
|
+
tzinfo = value.tzinfo
|
|
138
|
+
if tzinfo is None or tzinfo.utcoffset(value) is None:
|
|
139
|
+
return to_datetime_aware(value)
|
|
140
|
+
if not hasattr(tzinfo, "zone"):
|
|
141
|
+
return value.astimezone(LUMIBOT_DEFAULT_PYTZ)
|
|
142
|
+
return value
|
|
143
|
+
|
|
127
144
|
@property
|
|
128
145
|
def is_backtesting(self) -> bool:
|
|
129
146
|
"""Boolean flag indicating whether the strategy is running in backtesting mode."""
|
|
@@ -1389,8 +1406,8 @@ class _Strategy:
|
|
|
1389
1406
|
raise ValueError(f"`optionsource_class` must be a class. You passed in {optionsource_class}")
|
|
1390
1407
|
|
|
1391
1408
|
try:
|
|
1392
|
-
backtesting_start =
|
|
1393
|
-
backtesting_end =
|
|
1409
|
+
backtesting_start = self._normalize_backtest_datetime(backtesting_start)
|
|
1410
|
+
backtesting_end = self._normalize_backtest_datetime(backtesting_end)
|
|
1394
1411
|
except AttributeError:
|
|
1395
1412
|
get_logger(__name__).error(
|
|
1396
1413
|
"`backtesting_start` and `backtesting_end` must be datetime objects. \n"
|
|
@@ -1399,6 +1416,9 @@ class _Strategy:
|
|
|
1399
1416
|
)
|
|
1400
1417
|
return None
|
|
1401
1418
|
|
|
1419
|
+
get_logger(__name__).info("Backtest start = %s", backtesting_start)
|
|
1420
|
+
get_logger(__name__).info("Backtest end = %s", backtesting_end)
|
|
1421
|
+
|
|
1402
1422
|
self.verify_backtest_inputs(backtesting_start, backtesting_end)
|
|
1403
1423
|
|
|
1404
1424
|
if not self.IS_BACKTESTABLE:
|
|
@@ -1628,8 +1648,8 @@ class _Strategy:
|
|
|
1628
1648
|
if not isinstance(backtesting_end, datetime.datetime):
|
|
1629
1649
|
raise ValueError(f"`backtesting_end` must be a datetime object. You passed in {backtesting_end}")
|
|
1630
1650
|
|
|
1631
|
-
start_dt =
|
|
1632
|
-
end_dt =
|
|
1651
|
+
start_dt = cls._normalize_backtest_datetime(backtesting_start)
|
|
1652
|
+
end_dt = cls._normalize_backtest_datetime(backtesting_end)
|
|
1633
1653
|
|
|
1634
1654
|
# Check that backtesting end is after backtesting start
|
|
1635
1655
|
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:
|
|
@@ -445,7 +445,7 @@ class CcxtCacheDB:
|
|
|
445
445
|
if freq == "1d":
|
|
446
446
|
dt_range = pd.date_range(start=df.index.min(), end=df.index.max(), freq="D")
|
|
447
447
|
else:
|
|
448
|
-
dt_range = pd.date_range(start=df.index.min(), end=df.index.max(), freq="
|
|
448
|
+
dt_range = pd.date_range(start=df.index.min(), end=df.index.max(), freq="min")
|
|
449
449
|
|
|
450
450
|
df_complete = df.reindex(dt_range).ffill()
|
|
451
451
|
df_complete['missing'] = np.where(df_complete.index.isin(df.index), 0, 1)
|
|
@@ -1047,10 +1047,10 @@ def get_last_price_from_databento(
|
|
|
1047
1047
|
df = pd.DataFrame(data)
|
|
1048
1048
|
|
|
1049
1049
|
if not df.empty:
|
|
1050
|
-
# Get the last available price (close price of most recent bar)
|
|
1051
1050
|
if 'close' in df.columns:
|
|
1052
|
-
|
|
1053
|
-
if
|
|
1051
|
+
closes = df['close'].dropna()
|
|
1052
|
+
if not closes.empty:
|
|
1053
|
+
price = closes.iloc[-1]
|
|
1054
1054
|
logger.info(f"✓ SUCCESS: Got last price for {symbol_to_use}: {price}")
|
|
1055
1055
|
return float(price)
|
|
1056
1056
|
|