back-trader-python 1.4.0__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.
- back_trader_python-1.4.0.dist-info/METADATA +1491 -0
- back_trader_python-1.4.0.dist-info/RECORD +465 -0
- back_trader_python-1.4.0.dist-info/WHEEL +5 -0
- back_trader_python-1.4.0.dist-info/licenses/LICENSE +674 -0
- back_trader_python-1.4.0.dist-info/top_level.txt +1 -0
- backtrader/__init__.py +148 -0
- backtrader/_cerebro/__init__.py +5 -0
- backtrader/_cerebro/channel.py +382 -0
- backtrader/_cerebro/execution.py +377 -0
- backtrader/_cerebro/lifecycle.py +143 -0
- backtrader/_cerebro/notifications.py +150 -0
- backtrader/_cerebro/presentation.py +230 -0
- backtrader/_cerebro/registry.py +593 -0
- backtrader/_cerebro/runnext.py +551 -0
- backtrader/_cerebro/runonce.py +142 -0
- backtrader/analyzer.py +594 -0
- backtrader/analyzers/__init__.py +50 -0
- backtrader/analyzers/annualreturn.py +226 -0
- backtrader/analyzers/calmar.py +165 -0
- backtrader/analyzers/drawdown.py +287 -0
- backtrader/analyzers/leverage.py +112 -0
- backtrader/analyzers/logreturnsrolling.py +190 -0
- backtrader/analyzers/periodstats.py +153 -0
- backtrader/analyzers/positions.py +119 -0
- backtrader/analyzers/pyfolio.py +470 -0
- backtrader/analyzers/returns.py +192 -0
- backtrader/analyzers/sharpe.py +307 -0
- backtrader/analyzers/sharpe_ratio_stats.py +534 -0
- backtrader/analyzers/sqn.py +112 -0
- backtrader/analyzers/timereturn.py +192 -0
- backtrader/analyzers/total_value.py +75 -0
- backtrader/analyzers/tradeanalyzer.py +278 -0
- backtrader/analyzers/transactions.py +141 -0
- backtrader/analyzers/vwr.py +245 -0
- backtrader/bokeh/__init__.py +155 -0
- backtrader/bokeh/analyzers/__init__.py +13 -0
- backtrader/bokeh/analyzers/plot.py +192 -0
- backtrader/bokeh/analyzers/recorder.py +181 -0
- backtrader/bokeh/app.py +1094 -0
- backtrader/bokeh/live/__init__.py +11 -0
- backtrader/bokeh/live/client.py +352 -0
- backtrader/bokeh/live/datahandler.py +346 -0
- backtrader/bokeh/plot_adapter.py +200 -0
- backtrader/bokeh/schemes/__init__.py +14 -0
- backtrader/bokeh/schemes/blackly.py +76 -0
- backtrader/bokeh/schemes/scheme.py +150 -0
- backtrader/bokeh/schemes/tradimo.py +82 -0
- backtrader/bokeh/tab.py +125 -0
- backtrader/bokeh/tabs/__init__.py +30 -0
- backtrader/bokeh/tabs/analyzer.py +120 -0
- backtrader/bokeh/tabs/config.py +154 -0
- backtrader/bokeh/tabs/live.py +109 -0
- backtrader/bokeh/tabs/log.py +185 -0
- backtrader/bokeh/tabs/metadata.py +182 -0
- backtrader/bokeh/tabs/performance.py +359 -0
- backtrader/bokeh/tabs/source.py +70 -0
- backtrader/bokeh/utils/__init__.py +8 -0
- backtrader/bokeh/utils/helpers.py +167 -0
- backtrader/bokeh/webapp.py +164 -0
- backtrader/broker.py +478 -0
- backtrader/brokers/__init__.py +36 -0
- backtrader/brokers/bbroker.py +2576 -0
- backtrader/brokers/btapibroker.py +8227 -0
- backtrader/brokers/hft/__init__.py +89 -0
- backtrader/brokers/hft/binance_bbo.py +625 -0
- backtrader/brokers/hft/binance_bbo_compare.py +1398 -0
- backtrader/brokers/hft/examples.py +1228 -0
- backtrader/brokers/hft/exchange.py +380 -0
- backtrader/brokers/hft/latency.py +309 -0
- backtrader/brokers/hft/matching_core.py +572 -0
- backtrader/brokers/hft/queue.py +238 -0
- backtrader/brokers/hft/recorder.py +88 -0
- backtrader/brokers/hft/state.py +138 -0
- backtrader/brokers/impact_models.py +118 -0
- backtrader/brokers/mixbroker.py +895 -0
- backtrader/brokers/tickbroker.py +1991 -0
- backtrader/btrun/__init__.py +12 -0
- backtrader/btrun/btrun.py +1218 -0
- backtrader/cerebro.py +828 -0
- backtrader/channel.py +682 -0
- backtrader/channels/__init__.py +23 -0
- backtrader/channels/bridge.py +186 -0
- backtrader/channels/funding.py +248 -0
- backtrader/channels/live_queue.py +216 -0
- backtrader/channels/live_validator.py +294 -0
- backtrader/channels/orderbook.py +257 -0
- backtrader/channels/tick.py +202 -0
- backtrader/comminfo.py +665 -0
- backtrader/commissions/__init__.py +106 -0
- backtrader/commissions/ctpoption.py +993 -0
- backtrader/configs/account_config_example.yaml +8 -0
- backtrader/dataseries.py +379 -0
- backtrader/errors.py +106 -0
- backtrader/events.py +980 -0
- backtrader/feed.py +1523 -0
- backtrader/feeds/__init__.py +75 -0
- backtrader/feeds/barrier.py +2006 -0
- backtrader/feeds/blaze.py +118 -0
- backtrader/feeds/btapifeed.py +1538 -0
- backtrader/feeds/btcsv.py +203 -0
- backtrader/feeds/chainer.py +114 -0
- backtrader/feeds/cryptohftdata.py +164 -0
- backtrader/feeds/csvgeneric.py +1205 -0
- backtrader/feeds/ctpcohort.py +1051 -0
- backtrader/feeds/influxfeed.py +158 -0
- backtrader/feeds/livefeed.py +71 -0
- backtrader/feeds/mixed_channel.py +108 -0
- backtrader/feeds/mt4csv.py +42 -0
- backtrader/feeds/pandafeed.py +381 -0
- backtrader/feeds/quandl.py +256 -0
- backtrader/feeds/rollover.py +229 -0
- backtrader/feeds/sierrachart.py +30 -0
- backtrader/feeds/vchart.py +162 -0
- backtrader/feeds/vchartcsv.py +84 -0
- backtrader/feeds/vchartfile.py +153 -0
- backtrader/feeds/yahoo.py +399 -0
- backtrader/fillers.py +148 -0
- backtrader/filters/__init__.py +34 -0
- backtrader/filters/bsplitter.py +127 -0
- backtrader/filters/calendardays.py +121 -0
- backtrader/filters/datafiller.py +192 -0
- backtrader/filters/datafilter.py +74 -0
- backtrader/filters/daysteps.py +96 -0
- backtrader/filters/heikinashi.py +63 -0
- backtrader/filters/renko.py +164 -0
- backtrader/filters/session.py +289 -0
- backtrader/flt.py +80 -0
- backtrader/functions.py +960 -0
- backtrader/indicator.py +449 -0
- backtrader/indicators/__init__.py +148 -0
- backtrader/indicators/accdecoscillator.py +110 -0
- backtrader/indicators/aroon.py +300 -0
- backtrader/indicators/atr.py +315 -0
- backtrader/indicators/awesomeoscillator.py +122 -0
- backtrader/indicators/basicops.py +834 -0
- backtrader/indicators/bollinger.py +223 -0
- backtrader/indicators/cci.py +89 -0
- backtrader/indicators/channels_ext.py +83 -0
- backtrader/indicators/contrib/__init__.py +228 -0
- backtrader/indicators/contrib/absolutely_no_lag_lwma.py +28 -0
- backtrader/indicators/contrib/absolutely_no_lag_lwma_color.py +44 -0
- backtrader/indicators/contrib/accumulation_distribution_line.py +92 -0
- backtrader/indicators/contrib/adx_cross_hull_style_indicator.py +249 -0
- backtrader/indicators/contrib/adxdmi.py +34 -0
- backtrader/indicators/contrib/ai_acceleration_deceleration_oscillator.py +34 -0
- backtrader/indicators/contrib/altr_trend_signal_v22.py +85 -0
- backtrader/indicators/contrib/anchored_momentum_line.py +115 -0
- backtrader/indicators/contrib/any_range_cld_tail_indicator.py +82 -0
- backtrader/indicators/contrib/aroon_horn_sign_indicator.py +96 -0
- backtrader/indicators/contrib/aroon_oscillator_sign_alert.py +50 -0
- backtrader/indicators/contrib/arrows_curves_indicator.py +112 -0
- backtrader/indicators/contrib/as_ctrend_indicator.py +143 -0
- backtrader/indicators/contrib/asimmetric_stoch_nr_indicator.py +187 -0
- backtrader/indicators/contrib/atr_normalize_histogram.py +118 -0
- backtrader/indicators/contrib/average_change_candle.py +165 -0
- backtrader/indicators/contrib/bb_squeeze_indicator.py +60 -0
- backtrader/indicators/contrib/bezier_st_dev_indicator.py +135 -0
- backtrader/indicators/contrib/binary_wave_indicator.py +233 -0
- backtrader/indicators/contrib/blau_c_momentum_indicator.py +123 -0
- backtrader/indicators/contrib/blau_cmi_indicator.py +141 -0
- backtrader/indicators/contrib/blau_csi.py +76 -0
- backtrader/indicators/contrib/blau_ergodic.py +53 -0
- backtrader/indicators/contrib/blau_t_stoch_i.py +72 -0
- backtrader/indicators/contrib/blau_ts_stochastic.py +85 -0
- backtrader/indicators/contrib/blau_tvi.py +55 -0
- backtrader/indicators/contrib/brain_trend2_indicator.py +128 -0
- backtrader/indicators/contrib/brain_trend_signal_proxy.py +47 -0
- backtrader/indicators/contrib/brake_parb_indicator.py +85 -0
- backtrader/indicators/contrib/breakout_bars_trend_v2.py +121 -0
- backtrader/indicators/contrib/bsi_indicator.py +87 -0
- backtrader/indicators/contrib/bulls_bears_eyes.py +67 -0
- backtrader/indicators/contrib/bulls_power.py +56 -0
- backtrader/indicators/contrib/bw_wise_man1_signal.py +102 -0
- backtrader/indicators/contrib/bykov_trend_indicator.py +85 -0
- backtrader/indicators/contrib/candle_stop_color.py +46 -0
- backtrader/indicators/contrib/candles_x_smoothed_indicator.py +69 -0
- backtrader/indicators/contrib/candlesticks_bw.py +45 -0
- backtrader/indicators/contrib/caudate_x_period_candle_color.py +56 -0
- backtrader/indicators/contrib/cci_histogram_indicator.py +53 -0
- backtrader/indicators/contrib/cci_woodies_indicator.py +80 -0
- backtrader/indicators/contrib/center_of_gravity_candle_indicator.py +83 -0
- backtrader/indicators/contrib/center_of_gravity_indicator.py +70 -0
- backtrader/indicators/contrib/cg_oscillator.py +40 -0
- backtrader/indicators/contrib/close_line_cci.py +38 -0
- backtrader/indicators/contrib/close_price_fractals.py +47 -0
- backtrader/indicators/contrib/color3rd_gen_xma_indicator.py +122 -0
- backtrader/indicators/contrib/color_bb_candles_indicator.py +108 -0
- backtrader/indicators/contrib/color_coppock_indicator.py +157 -0
- backtrader/indicators/contrib/color_hma.py +71 -0
- backtrader/indicators/contrib/color_j_variation_indicator.py +53 -0
- backtrader/indicators/contrib/color_metro_de_marker_indicator.py +78 -0
- backtrader/indicators/contrib/color_metro_stochastic_indicator.py +93 -0
- backtrader/indicators/contrib/color_metro_wpr_indicator.py +85 -0
- backtrader/indicators/contrib/color_schaff_de_marker_trend_cycle.py +92 -0
- backtrader/indicators/contrib/color_schaff_trend_cycle_indicator.py +203 -0
- backtrader/indicators/contrib/color_step_xccx_indicator.py +193 -0
- backtrader/indicators/contrib/color_x2_ma.py +49 -0
- backtrader/indicators/contrib/color_x_derivative.py +63 -0
- backtrader/indicators/contrib/color_zerolag_de_marker.py +84 -0
- backtrader/indicators/contrib/corrected_average_indicator.py +127 -0
- backtrader/indicators/contrib/darvas_boxes_system.py +73 -0
- backtrader/indicators/contrib/dema_range_channel_color.py +42 -0
- backtrader/indicators/contrib/derivative_indicator.py +95 -0
- backtrader/indicators/contrib/digital_ft01_indicator.py +112 -0
- backtrader/indicators/contrib/digital_macd.py +200 -0
- backtrader/indicators/contrib/donchian_channels_system.py +45 -0
- backtrader/indicators/contrib/dots_indicator.py +93 -0
- backtrader/indicators/contrib/ef_distance_indicator.py +82 -0
- backtrader/indicators/contrib/ema_rsi_va.py +80 -0
- backtrader/indicators/contrib/envelopes_jp_alonso.py +32 -0
- backtrader/indicators/contrib/f2a_ao_indicator.py +120 -0
- backtrader/indicators/contrib/fatl_filter.py +179 -0
- backtrader/indicators/contrib/fibo_candles_indicator.py +78 -0
- backtrader/indicators/contrib/fine_tuning_ma.py +100 -0
- backtrader/indicators/contrib/fisher_org_v1.py +102 -0
- backtrader/indicators/contrib/fisher_org_v1_sign.py +118 -0
- backtrader/indicators/contrib/force_index_ema.py +96 -0
- backtrader/indicators/contrib/force_index_ema_2.py +27 -0
- backtrader/indicators/contrib/forecast_oscilator.py +145 -0
- backtrader/indicators/contrib/fractal_amambk.py +81 -0
- backtrader/indicators/contrib/frama_series.py +84 -0
- backtrader/indicators/contrib/frasm_av2_indicator.py +104 -0
- backtrader/indicators/contrib/go_indicator.py +93 -0
- backtrader/indicators/contrib/hlr_indicator.py +95 -0
- backtrader/indicators/contrib/hma.py +50 -0
- backtrader/indicators/contrib/i4_drfv2.py +34 -0
- backtrader/indicators/contrib/i4_drfv3.py +38 -0
- backtrader/indicators/contrib/i_anch_mom_indicator.py +72 -0
- backtrader/indicators/contrib/i_de_marker_sign_indicator.py +64 -0
- backtrader/indicators/contrib/i_gap_indicator.py +45 -0
- backtrader/indicators/contrib/i_stoch_komposter_indicator.py +77 -0
- backtrader/indicators/contrib/i_trend_indicator.py +125 -0
- backtrader/indicators/contrib/iamma_indicator.py +39 -0
- backtrader/indicators/contrib/indexed_moving_average.py +33 -0
- backtrader/indicators/contrib/instantaneous_trend_filter_indicator.py +51 -0
- backtrader/indicators/contrib/inverse_reaction_indicator.py +41 -0
- backtrader/indicators/contrib/irsi_sign_indicator.py +95 -0
- backtrader/indicators/contrib/iwpr_sign_indicator.py +59 -0
- backtrader/indicators/contrib/j_brain_trend1_sig_indicator.py +233 -0
- backtrader/indicators/contrib/j_tpo_proxy.py +32 -0
- backtrader/indicators/contrib/jma_slope_indicator.py +73 -0
- backtrader/indicators/contrib/kalman_filter_indicator.py +119 -0
- backtrader/indicators/contrib/kalman_filter_line.py +127 -0
- backtrader/indicators/contrib/kama_indicator.py +150 -0
- backtrader/indicators/contrib/karacatica_indicator.py +99 -0
- backtrader/indicators/contrib/kdj_indicator.py +59 -0
- backtrader/indicators/contrib/kwan_ccc_indicator.py +195 -0
- backtrader/indicators/contrib/kwan_nrp_indicator.py +113 -0
- backtrader/indicators/contrib/kwan_rdp_indicator.py +192 -0
- backtrader/indicators/contrib/laguerre_adx_indicator.py +85 -0
- backtrader/indicators/contrib/laguerre_filter_indicator.py +66 -0
- backtrader/indicators/contrib/laguerre_plus_di_proxy.py +57 -0
- backtrader/indicators/contrib/laguerre_roc_indicator.py +81 -0
- backtrader/indicators/contrib/le_man_signal_indicator.py +63 -0
- backtrader/indicators/contrib/linear_reg_slope_v2_indicator.py +136 -0
- backtrader/indicators/contrib/loco_indicator.py +88 -0
- backtrader/indicators/contrib/lrma_indicator.py +185 -0
- backtrader/indicators/contrib/lsma_angle_indicator.py +106 -0
- backtrader/indicators/contrib/ma_rounding_channel_indicator.py +149 -0
- backtrader/indicators/contrib/macd2_indicator.py +61 -0
- backtrader/indicators/contrib/macd_candle_indicator.py +80 -0
- backtrader/indicators/contrib/malr_indicator.py +77 -0
- backtrader/indicators/contrib/momentum_candle_sign_indicator.py +51 -0
- backtrader/indicators/contrib/moving_average_fn_indicator.py +139 -0
- backtrader/indicators/contrib/mt5_stochastic_close_close.py +57 -0
- backtrader/indicators/contrib/muv_nor_diff_cloud_indicator.py +107 -0
- backtrader/indicators/contrib/non_lag_dot_indicator.py +124 -0
- backtrader/indicators/contrib/nrtr_extr_indicator.py +95 -0
- backtrader/indicators/contrib/nrtr_indicator.py +95 -0
- backtrader/indicators/contrib/p_channel_system.py +40 -0
- backtrader/indicators/contrib/percent_envelope.py +37 -0
- backtrader/indicators/contrib/percentage_crossover_channel.py +47 -0
- backtrader/indicators/contrib/pivot_zig_zag_proxy.py +47 -0
- backtrader/indicators/contrib/price_channel_stop_indicator.py +104 -0
- backtrader/indicators/contrib/price_extreme_channel.py +35 -0
- backtrader/indicators/contrib/qqe_cloud_indicator.py +129 -0
- backtrader/indicators/contrib/ravi_indicator.py +40 -0
- backtrader/indicators/contrib/raw_close_close_stochastic.py +74 -0
- backtrader/indicators/contrib/rd_trend_trigger_indicator.py +51 -0
- backtrader/indicators/contrib/renko_level.py +85 -0
- backtrader/indicators/contrib/renko_line_break.py +91 -0
- backtrader/indicators/contrib/rftl_indicator.py +41 -0
- backtrader/indicators/contrib/rkd_indicator.py +53 -0
- backtrader/indicators/contrib/roc2_vg_indicator.py +68 -0
- backtrader/indicators/contrib/rsi_histogram_indicator.py +43 -0
- backtrader/indicators/contrib/rsi_slowdown.py +57 -0
- backtrader/indicators/contrib/rsioma_v2.py +41 -0
- backtrader/indicators/contrib/rvi_histogram_indicator.py +107 -0
- backtrader/indicators/contrib/safe_adx.py +89 -0
- backtrader/indicators/contrib/shared_strategy_indicators.py +1651 -0
- backtrader/indicators/contrib/sidus_indicator.py +105 -0
- backtrader/indicators/contrib/silver_trend_indicator.py +79 -0
- backtrader/indicators/contrib/sliding_range_color.py +56 -0
- backtrader/indicators/contrib/slow_stoch.py +42 -0
- backtrader/indicators/contrib/smoothed_adx_indicator.py +86 -0
- backtrader/indicators/contrib/smoothed_rsi.py +31 -0
- backtrader/indicators/contrib/spearman_rank_correlation_histogram.py +60 -0
- backtrader/indicators/contrib/stalin_indicator.py +152 -0
- backtrader/indicators/contrib/starter_laguerre_filter.py +62 -0
- backtrader/indicators/contrib/step_manrtr_indicator.py +137 -0
- backtrader/indicators/contrib/stochastic_histogram_indicator.py +143 -0
- backtrader/indicators/contrib/t3_alarm_indicator.py +125 -0
- backtrader/indicators/contrib/t3_average.py +76 -0
- backtrader/indicators/contrib/t3_indicator.py +40 -0
- backtrader/indicators/contrib/the20s_v020_signal.py +93 -0
- backtrader/indicators/contrib/three_candles_indicator.py +70 -0
- backtrader/indicators/contrib/three_line_break_indicator.py +64 -0
- backtrader/indicators/contrib/time_line.py +57 -0
- backtrader/indicators/contrib/trading_channel_index_proxy.py +48 -0
- backtrader/indicators/contrib/trend_arrows_indicator.py +109 -0
- backtrader/indicators/contrib/trend_continuation_indicator.py +127 -0
- backtrader/indicators/contrib/trend_intensity_index_proxy.py +51 -0
- backtrader/indicators/contrib/trend_manager_indicator.py +39 -0
- backtrader/indicators/contrib/tri_x_candle_indicator.py +51 -0
- backtrader/indicators/contrib/trigger_line.py +66 -0
- backtrader/indicators/contrib/triple_ema_rate.py +34 -0
- backtrader/indicators/contrib/trvi_indicator.py +194 -0
- backtrader/indicators/contrib/two_pb_ideal_xosma_indicator.py +127 -0
- backtrader/indicators/contrib/ultra_absolutely_no_lag_lwma_color.py +92 -0
- backtrader/indicators/contrib/ultra_wpr_indicator.py +173 -0
- backtrader/indicators/contrib/up_down_candle_strength.py +68 -0
- backtrader/indicators/contrib/vinin_i_trend_indicator.py +139 -0
- backtrader/indicators/contrib/volume_weighted_ma_indicator.py +78 -0
- backtrader/indicators/contrib/volume_weighted_ma_st_dev_indicator.py +111 -0
- backtrader/indicators/contrib/vwap_close_indicator.py +65 -0
- backtrader/indicators/contrib/vwma_candle.py +57 -0
- backtrader/indicators/contrib/vwma_digit_system.py +70 -0
- backtrader/indicators/contrib/wami.py +43 -0
- backtrader/indicators/contrib/wprsi_signal_indicator.py +105 -0
- backtrader/indicators/contrib/x_de_marker_histogram_vol_direct_indicator.py +145 -0
- backtrader/indicators/contrib/x_fisher_indicator.py +64 -0
- backtrader/indicators/contrib/xcci_histogram_vol_direct_indicator.py +56 -0
- backtrader/indicators/contrib/xcci_histogram_vol_indicator.py +85 -0
- backtrader/indicators/contrib/xma_ichimoku.py +163 -0
- backtrader/indicators/contrib/xma_ishimoku_channel_indicator.py +65 -0
- backtrader/indicators/contrib/xma_ishimoku_line.py +68 -0
- backtrader/indicators/contrib/xma_range_bands_indicator.py +107 -0
- backtrader/indicators/contrib/xmacd_indicator.py +70 -0
- backtrader/indicators/contrib/xrsi_de_marker_histogram.py +67 -0
- backtrader/indicators/contrib/xrsi_histogram_vol_direct_indicator.py +52 -0
- backtrader/indicators/contrib/xrsi_histogram_vol_indicator.py +81 -0
- backtrader/indicators/contrib/xrvi_indicator.py +130 -0
- backtrader/indicators/contrib/zero_lag_macd.py +36 -0
- backtrader/indicators/contrib/zig_zag_recent_pivot_signal.py +90 -0
- backtrader/indicators/contrib/zpf_indicator.py +115 -0
- backtrader/indicators/crossover.py +337 -0
- backtrader/indicators/dema.py +175 -0
- backtrader/indicators/demarker.py +270 -0
- backtrader/indicators/deviation.py +284 -0
- backtrader/indicators/directionalmove.py +1071 -0
- backtrader/indicators/dma.py +112 -0
- backtrader/indicators/dpo.py +96 -0
- backtrader/indicators/dv2.py +56 -0
- backtrader/indicators/ema.py +145 -0
- backtrader/indicators/envelope.py +475 -0
- backtrader/indicators/hadelta.py +198 -0
- backtrader/indicators/heikinashi.py +153 -0
- backtrader/indicators/hma.py +153 -0
- backtrader/indicators/hurst.py +151 -0
- backtrader/indicators/ichimoku.py +267 -0
- backtrader/indicators/kama.py +181 -0
- backtrader/indicators/kst.py +159 -0
- backtrader/indicators/lrsi.py +125 -0
- backtrader/indicators/mabase.py +147 -0
- backtrader/indicators/macd.py +322 -0
- backtrader/indicators/momentum.py +267 -0
- backtrader/indicators/moneyflow.py +237 -0
- backtrader/indicators/mt5atr.py +124 -0
- backtrader/indicators/myind.py +179 -0
- backtrader/indicators/obv.py +94 -0
- backtrader/indicators/ols.py +265 -0
- backtrader/indicators/oscillator.py +161 -0
- backtrader/indicators/percentchange.py +83 -0
- backtrader/indicators/percentrank.py +46 -0
- backtrader/indicators/pivotpoint.py +469 -0
- backtrader/indicators/prettygoodoscillator.py +113 -0
- backtrader/indicators/priceops_ext.py +123 -0
- backtrader/indicators/priceoscillator.py +262 -0
- backtrader/indicators/psar.py +212 -0
- backtrader/indicators/rmi.py +69 -0
- backtrader/indicators/rsi.py +440 -0
- backtrader/indicators/sma.py +141 -0
- backtrader/indicators/smma.py +116 -0
- backtrader/indicators/spread.py +54 -0
- backtrader/indicators/stochastic.py +263 -0
- backtrader/indicators/supertrend.py +436 -0
- backtrader/indicators/trend_ext.py +105 -0
- backtrader/indicators/trix.py +202 -0
- backtrader/indicators/tsi.py +155 -0
- backtrader/indicators/ultimateoscillator.py +158 -0
- backtrader/indicators/vortex.py +62 -0
- backtrader/indicators/williams.py +194 -0
- backtrader/indicators/wma.py +103 -0
- backtrader/indicators/zlema.py +135 -0
- backtrader/indicators/zlind.py +104 -0
- backtrader/linebuffer.py +3155 -0
- backtrader/lineiterator.py +2911 -0
- backtrader/lineroot.py +1106 -0
- backtrader/lineseries.py +2559 -0
- backtrader/live_trading/__init__.py +31 -0
- backtrader/live_trading/interface.py +404 -0
- backtrader/mathsupport.py +94 -0
- backtrader/metabase.py +1804 -0
- backtrader/mixins/__init__.py +21 -0
- backtrader/mixins/singleton.py +118 -0
- backtrader/observer.py +106 -0
- backtrader/observers/__init__.py +45 -0
- backtrader/observers/benchmark.py +126 -0
- backtrader/observers/broker.py +184 -0
- backtrader/observers/buysell.py +144 -0
- backtrader/observers/drawdown.py +161 -0
- backtrader/observers/logreturns.py +113 -0
- backtrader/observers/timereturn.py +86 -0
- backtrader/observers/trade_logger.py +2972 -0
- backtrader/observers/tradelogger.py +6 -0
- backtrader/observers/trades.py +258 -0
- backtrader/order.py +1114 -0
- backtrader/parameters.py +2345 -0
- backtrader/plot/__init__.py +54 -0
- backtrader/plot/finance.py +1022 -0
- backtrader/plot/formatters.py +200 -0
- backtrader/plot/locator.py +353 -0
- backtrader/plot/multicursor.py +495 -0
- backtrader/plot/plot.py +2500 -0
- backtrader/plot/plot_plotly.py +1351 -0
- backtrader/plot/scheme.py +253 -0
- backtrader/plot/utils.py +104 -0
- backtrader/position.py +290 -0
- backtrader/position_modes.py +132 -0
- backtrader/profiles.py +254 -0
- backtrader/reports/__init__.py +39 -0
- backtrader/reports/charts.py +371 -0
- backtrader/reports/performance.py +620 -0
- backtrader/reports/reporter.py +660 -0
- backtrader/resamplerfilter.py +1001 -0
- backtrader/signal.py +118 -0
- backtrader/signals/__init__.py +17 -0
- backtrader/sizer.py +114 -0
- backtrader/sizers/__init__.py +26 -0
- backtrader/sizers/fixedsize.py +161 -0
- backtrader/sizers/percents_sizer.py +119 -0
- backtrader/store.py +221 -0
- backtrader/stores/__init__.py +33 -0
- backtrader/stores/btapistore.py +15506 -0
- backtrader/stores/livestore.py +137 -0
- backtrader/stores/vchartfile.py +96 -0
- backtrader/strategy.py +3655 -0
- backtrader/talib.py +280 -0
- backtrader/test_helpers.py +96 -0
- backtrader/timer.py +358 -0
- backtrader/trade.py +442 -0
- backtrader/tradingcal.py +361 -0
- backtrader/utils/__init__.py +68 -0
- backtrader/utils/autodict.py +251 -0
- backtrader/utils/date.py +71 -0
- backtrader/utils/dateintern.py +509 -0
- backtrader/utils/flushfile.py +94 -0
- backtrader/utils/fractal.py +101 -0
- backtrader/utils/get_metrics.py +101 -0
- backtrader/utils/load_data.py +209 -0
- backtrader/utils/log_message.py +998 -0
- backtrader/utils/ordereddefaultdict.py +75 -0
- backtrader/utils/py3.py +296 -0
- backtrader/version.py +21 -0
- backtrader/writer.py +372 -0
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
"""Cerebro event-driven engine mixin (iteration 28 split).
|
|
2
|
+
|
|
3
|
+
Moved verbatim from ``backtrader/cerebro.py``: ``_runnext`` (modern, with
|
|
4
|
+
the direct-load fast path) and ``_runnext_old`` (oldsync). Hot loop - any
|
|
5
|
+
edit here must be justified against AC28-09.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import datetime
|
|
9
|
+
from datetime import timezone
|
|
10
|
+
|
|
11
|
+
from ..brokers import BackBroker
|
|
12
|
+
from ..feed import AbstractDataBase
|
|
13
|
+
from ..strategy import Strategy
|
|
14
|
+
from ..utils import date2num
|
|
15
|
+
from ..utils.dateintern import _num2date_cached
|
|
16
|
+
from ..utils.log_message import get_logger
|
|
17
|
+
|
|
18
|
+
UTC = timezone.utc
|
|
19
|
+
|
|
20
|
+
# Keep the historical logger name (D28-04.6): routing/filters must not change.
|
|
21
|
+
logger = get_logger("backtrader.cerebro")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class RunNextMixin:
|
|
25
|
+
"""Event-driven engine half of Cerebro (see module docstring)."""
|
|
26
|
+
|
|
27
|
+
# Old runnext method, similar to runnext
|
|
28
|
+
def _runnext_old(self, runstrats):
|
|
29
|
+
"""
|
|
30
|
+
Actual implementation of run in full next mode. All objects have its
|
|
31
|
+
`next` method invoked on each data arrival
|
|
32
|
+
"""
|
|
33
|
+
data0 = self.datas[0]
|
|
34
|
+
d0ret = True
|
|
35
|
+
while d0ret or d0ret is None:
|
|
36
|
+
lastret = False
|
|
37
|
+
# Notify anything from the store even before moving datas
|
|
38
|
+
# because datas may not move due to an error reported by the store
|
|
39
|
+
self._storenotify()
|
|
40
|
+
if self._event_stop: # stop if requested
|
|
41
|
+
return
|
|
42
|
+
self._datanotify()
|
|
43
|
+
if self._event_stop: # stop if requested
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
d0ret = data0.next()
|
|
47
|
+
if d0ret:
|
|
48
|
+
for data in self.datas[1:]:
|
|
49
|
+
if not data.next(datamaster=data0): # no delivery
|
|
50
|
+
data._check(forcedata=data0) # check forcing output
|
|
51
|
+
data.next(datamaster=data0) # retry
|
|
52
|
+
|
|
53
|
+
elif d0ret is None:
|
|
54
|
+
# meant for things like live feeds which may not produce a bar
|
|
55
|
+
# at the moment but need the loop to run for notifications and
|
|
56
|
+
# getting resample and others to produce timely bars
|
|
57
|
+
data0._check()
|
|
58
|
+
for data in self.datas[1:]:
|
|
59
|
+
data._check()
|
|
60
|
+
else:
|
|
61
|
+
lastret = data0._last()
|
|
62
|
+
for data in self.datas[1:]:
|
|
63
|
+
lastret += data._last(datamaster=data0)
|
|
64
|
+
|
|
65
|
+
if not lastret:
|
|
66
|
+
# Only go extra round if something was changed by "lasts"
|
|
67
|
+
break
|
|
68
|
+
|
|
69
|
+
# Datas may have generated a new notification after next
|
|
70
|
+
self._datanotify()
|
|
71
|
+
if self._event_stop: # stop if requested
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
self._brokernotify()
|
|
75
|
+
if self._event_stop: # stop if requested
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
if d0ret or lastret: # bars produced by data or filters
|
|
79
|
+
for strat in runstrats:
|
|
80
|
+
strat._next()
|
|
81
|
+
if self._event_stop: # stop if requested
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
self._next_writers(runstrats)
|
|
85
|
+
|
|
86
|
+
# Last notification chance before stopping
|
|
87
|
+
self._datanotify()
|
|
88
|
+
if self._event_stop: # stop if requested
|
|
89
|
+
return
|
|
90
|
+
self._storenotify()
|
|
91
|
+
if self._event_stop: # stop if requested
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
# runnext method, core of the framework, event-driven core for data execution
|
|
95
|
+
def _runnext(self, runstrats):
|
|
96
|
+
"""Actual implementation of run in full next mode.
|
|
97
|
+
|
|
98
|
+
All objects have their ``next`` method invoked on each data arrival.
|
|
99
|
+
|
|
100
|
+
The loop has four phases per iteration:
|
|
101
|
+
|
|
102
|
+
1. **Notification**: store and data notifications dispatched.
|
|
103
|
+
2. **Feed advance**: each data feed is advanced; ``d0ret`` computed.
|
|
104
|
+
3. **Time alignment**: feeds aligned to master datetime ``dt0``;
|
|
105
|
+
slower feeds rewound, faster feeds tick-filled.
|
|
106
|
+
4. **Strategy dispatch**: timers fired, broker notified, strategies
|
|
107
|
+
receive ``_next()`` / ``_next_open()``.
|
|
108
|
+
"""
|
|
109
|
+
try:
|
|
110
|
+
# Sort data by time period
|
|
111
|
+
datas = sorted(self.datas, key=lambda x: (x._timeframe, x._compression))
|
|
112
|
+
# Other data
|
|
113
|
+
datas1 = datas[1:]
|
|
114
|
+
# Main data
|
|
115
|
+
data0 = datas[0]
|
|
116
|
+
has_qcheck = any(d.p.qcheck for d in datas)
|
|
117
|
+
cheat_on_open = self.p.cheat_on_open
|
|
118
|
+
has_timers = bool(self._timers)
|
|
119
|
+
has_timerscheat = bool(self._timerscheat)
|
|
120
|
+
has_stores = bool(self.stores)
|
|
121
|
+
has_runwriters = bool(self.runwriters)
|
|
122
|
+
if len(runstrats) == 1:
|
|
123
|
+
single_runstrat = runstrats[0]
|
|
124
|
+
single_runstrat_next = single_runstrat._next
|
|
125
|
+
single_runstrat_next_open = single_runstrat._next_open
|
|
126
|
+
else:
|
|
127
|
+
single_runstrat = None
|
|
128
|
+
single_runstrat_next = None
|
|
129
|
+
idle_notifiers = tuple(
|
|
130
|
+
strat.notify_idle
|
|
131
|
+
for strat in runstrats
|
|
132
|
+
if type(strat).notify_idle is not Strategy.notify_idle
|
|
133
|
+
)
|
|
134
|
+
d0ret = True
|
|
135
|
+
# index for resample only, not replay
|
|
136
|
+
rsonly = [i for i, x in enumerate(datas) if x.resampling and not x.replaying]
|
|
137
|
+
# Check if only doing resample
|
|
138
|
+
onlyresample = len(datas) == len(rsonly)
|
|
139
|
+
# Check if no data needs resample
|
|
140
|
+
noresample = not rsonly
|
|
141
|
+
# Number of cloned data
|
|
142
|
+
clonecount = sum(d._clone for d in datas)
|
|
143
|
+
# Number of data
|
|
144
|
+
ldatas = len(datas)
|
|
145
|
+
single_data = ldatas == 1
|
|
146
|
+
single_default_datanotify = (
|
|
147
|
+
single_data and type(data0).get_notifications is AbstractDataBase.get_notifications
|
|
148
|
+
)
|
|
149
|
+
single_default_haslivedata = (
|
|
150
|
+
single_data and type(data0).haslivedata is AbstractDataBase.haslivedata
|
|
151
|
+
)
|
|
152
|
+
data0_datetime_line = data0.datetime if single_data else None
|
|
153
|
+
broker = self._broker
|
|
154
|
+
broker_next = broker.next
|
|
155
|
+
broker_next_without_bar = bool(getattr(broker, "next_without_bar", False))
|
|
156
|
+
broker_userhist = getattr(broker, "_userhist", None)
|
|
157
|
+
broker_fundhist = getattr(broker, "_fundhist", None)
|
|
158
|
+
default_broker_notifications = (
|
|
159
|
+
type(broker).get_notification is BackBroker.get_notification
|
|
160
|
+
)
|
|
161
|
+
default_backbroker_next = (
|
|
162
|
+
default_broker_notifications and type(broker).next is BackBroker.next
|
|
163
|
+
)
|
|
164
|
+
if default_broker_notifications:
|
|
165
|
+
broker_notifications = broker.notifs
|
|
166
|
+
else:
|
|
167
|
+
broker_notifications = None
|
|
168
|
+
broker_get_notification = broker.get_notification
|
|
169
|
+
if default_backbroker_next:
|
|
170
|
+
broker_pending = broker.pending
|
|
171
|
+
broker_submitted = broker.submitted
|
|
172
|
+
broker_toactivate = broker._toactivate
|
|
173
|
+
broker_cash_addition = broker._cash_addition
|
|
174
|
+
broker_dual_side_mode = broker._dual_side_mode
|
|
175
|
+
else:
|
|
176
|
+
broker_pending = None
|
|
177
|
+
broker_submitted = None
|
|
178
|
+
broker_toactivate = None
|
|
179
|
+
broker_cash_addition = None
|
|
180
|
+
broker_dual_side_mode = False
|
|
181
|
+
data0_direct_load = None
|
|
182
|
+
if single_data and not has_qcheck and single_default_haslivedata:
|
|
183
|
+
try:
|
|
184
|
+
if data0._runnext_direct_load_ready():
|
|
185
|
+
data0_direct_load = getattr(data0, "_runnext_direct_load", data0.load)
|
|
186
|
+
except AttributeError:
|
|
187
|
+
data0_direct_load = None
|
|
188
|
+
if data0_direct_load is not None and single_runstrat is not None:
|
|
189
|
+
try:
|
|
190
|
+
if (
|
|
191
|
+
single_runstrat._fast_simple_clock_update
|
|
192
|
+
and single_runstrat._single_clock_data is data0
|
|
193
|
+
and type(single_runstrat)._next is Strategy._next
|
|
194
|
+
):
|
|
195
|
+
single_runstrat_next = single_runstrat._next_fast_simple_direct_clock
|
|
196
|
+
object.__setattr__(single_runstrat, "_next", single_runstrat_next)
|
|
197
|
+
except AttributeError:
|
|
198
|
+
logger.debug("runnext:200 ignored AttributeError")
|
|
199
|
+
# Number of non-cloned data
|
|
200
|
+
ldatas_noclones = ldatas - clonecount
|
|
201
|
+
# Default dt0 at max time
|
|
202
|
+
dt0 = date2num(datetime.datetime.max) - 2 # default at max
|
|
203
|
+
if (
|
|
204
|
+
data0_direct_load is not None
|
|
205
|
+
and single_runstrat_next is not None
|
|
206
|
+
and getattr(single_runstrat_next, "__func__", None)
|
|
207
|
+
is Strategy._next_fast_simple_direct_clock
|
|
208
|
+
and default_broker_notifications
|
|
209
|
+
and default_backbroker_next
|
|
210
|
+
and single_default_datanotify
|
|
211
|
+
and not has_timers
|
|
212
|
+
and not has_timerscheat
|
|
213
|
+
and not cheat_on_open
|
|
214
|
+
and not has_stores
|
|
215
|
+
and not has_runwriters
|
|
216
|
+
and not broker_userhist
|
|
217
|
+
and not broker_fundhist
|
|
218
|
+
):
|
|
219
|
+
if data0.notifs:
|
|
220
|
+
self._datanotify()
|
|
221
|
+
if self._event_stop:
|
|
222
|
+
return
|
|
223
|
+
quicknotify = self.p.quicknotify
|
|
224
|
+
strat_forward_line = single_runstrat._single_line_forward_line
|
|
225
|
+
strat_clock_datetime_line = single_runstrat._single_clock_datetime_line
|
|
226
|
+
strat_forward_append = strat_forward_line.array.append
|
|
227
|
+
strat_clock_datetime_array = strat_clock_datetime_line.array
|
|
228
|
+
strat_dlens = single_runstrat._dlens
|
|
229
|
+
strat_minperiod = single_runstrat._single_minperiod
|
|
230
|
+
strat_minperiod_len_line = single_runstrat._single_minperiod_len_line
|
|
231
|
+
strat_minperstatus = strat_minperiod - strat_minperiod_len_line.lencount
|
|
232
|
+
strat_orderspending = single_runstrat._orderspending
|
|
233
|
+
strat_tradespending = single_runstrat._tradespending
|
|
234
|
+
strat_dict = single_runstrat.__dict__
|
|
235
|
+
strat_next = single_runstrat.next
|
|
236
|
+
strat_nextstart = single_runstrat.nextstart
|
|
237
|
+
strat_prenext = single_runstrat.prenext
|
|
238
|
+
while True:
|
|
239
|
+
if not data0_direct_load():
|
|
240
|
+
break
|
|
241
|
+
|
|
242
|
+
if not (
|
|
243
|
+
broker._no_open_positions
|
|
244
|
+
and not broker_pending
|
|
245
|
+
and not broker_submitted
|
|
246
|
+
and not broker_toactivate
|
|
247
|
+
and not broker_cash_addition
|
|
248
|
+
and not broker_dual_side_mode
|
|
249
|
+
and not broker_notifications
|
|
250
|
+
):
|
|
251
|
+
broker_next()
|
|
252
|
+
|
|
253
|
+
while broker_notifications:
|
|
254
|
+
order = broker_notifications.popleft()
|
|
255
|
+
owner = order.owner
|
|
256
|
+
if owner is None:
|
|
257
|
+
owner = single_runstrat
|
|
258
|
+
owner._addnotification(order, quicknotify=quicknotify)
|
|
259
|
+
|
|
260
|
+
if self._event_stop:
|
|
261
|
+
return
|
|
262
|
+
|
|
263
|
+
if strat_orderspending or strat_tradespending:
|
|
264
|
+
Strategy._next(single_runstrat)
|
|
265
|
+
strat_orderspending = single_runstrat._orderspending
|
|
266
|
+
strat_tradespending = single_runstrat._tradespending
|
|
267
|
+
strat_minperstatus = single_runstrat._minperstatus
|
|
268
|
+
else:
|
|
269
|
+
dt_value = strat_clock_datetime_array[strat_clock_datetime_line._idx]
|
|
270
|
+
strat_forward_line._idx += 1
|
|
271
|
+
strat_forward_line.lencount += 1
|
|
272
|
+
strat_forward_append(dt_value)
|
|
273
|
+
strat_dlens[0] = strat_clock_datetime_line.lencount
|
|
274
|
+
|
|
275
|
+
strat_minperstatus -= 1
|
|
276
|
+
strat_dict["_minperstatus"] = strat_minperstatus
|
|
277
|
+
if strat_minperstatus < 0:
|
|
278
|
+
strat_next()
|
|
279
|
+
elif strat_minperstatus == 0:
|
|
280
|
+
strat_nextstart()
|
|
281
|
+
else:
|
|
282
|
+
strat_prenext()
|
|
283
|
+
if self._event_stop:
|
|
284
|
+
return
|
|
285
|
+
|
|
286
|
+
if data0.notifs:
|
|
287
|
+
self._datanotify()
|
|
288
|
+
return
|
|
289
|
+
# Note: 'while True' (not 'while d0ret or d0ret is None') is intentional:
|
|
290
|
+
# when d0ret becomes False, the else branch still runs _last() on feeds
|
|
291
|
+
# and only breaks if no feed produces additional data.
|
|
292
|
+
while True:
|
|
293
|
+
# if any has live data in the buffer, no data will wait anything
|
|
294
|
+
# If any live data exists, newqcheck is False
|
|
295
|
+
if single_data:
|
|
296
|
+
newqcheck = True if single_default_haslivedata else not data0.haslivedata()
|
|
297
|
+
else:
|
|
298
|
+
newqcheck = not any(d.haslivedata() for d in datas)
|
|
299
|
+
# If live data exists
|
|
300
|
+
if not newqcheck:
|
|
301
|
+
# If no data has reached the live status or all, wait for
|
|
302
|
+
# the next incoming data
|
|
303
|
+
# livecount is the number of live data
|
|
304
|
+
if single_data:
|
|
305
|
+
livecount = data0._laststatus == data0.LIVE
|
|
306
|
+
else:
|
|
307
|
+
livecount = sum(d._laststatus == d.LIVE for d in datas)
|
|
308
|
+
# Override qcheck for mixed live/historical: wait only when
|
|
309
|
+
# no feeds are LIVE or ALL non-clone feeds are LIVE.
|
|
310
|
+
# When only some feeds are LIVE, skip wait for faster iteration.
|
|
311
|
+
newqcheck = not livecount or livecount == ldatas_noclones
|
|
312
|
+
|
|
313
|
+
lastret = False
|
|
314
|
+
# Notify anything from the store even before moving datas
|
|
315
|
+
# because datas may not move due to an error reported by the store
|
|
316
|
+
# Notify store related info
|
|
317
|
+
if has_stores:
|
|
318
|
+
self._storenotify()
|
|
319
|
+
if self._event_stop: # stop if requested
|
|
320
|
+
return
|
|
321
|
+
# Notify data related info
|
|
322
|
+
if not single_default_datanotify or data0.notifs:
|
|
323
|
+
self._datanotify()
|
|
324
|
+
if self._event_stop: # stop if requested
|
|
325
|
+
return
|
|
326
|
+
|
|
327
|
+
# record starting time and tell feeds to discount the elapsed time
|
|
328
|
+
# from the qcheck value
|
|
329
|
+
# Record start time and notify feed to subtract elapsed time from qcheck
|
|
330
|
+
if data0_direct_load is not None:
|
|
331
|
+
drets = (data0_direct_load(),)
|
|
332
|
+
else:
|
|
333
|
+
drets = []
|
|
334
|
+
if data0_direct_load is None and newqcheck and has_qcheck:
|
|
335
|
+
qstart = datetime.datetime.now(UTC)
|
|
336
|
+
for d in datas:
|
|
337
|
+
qlapse = datetime.datetime.now(UTC) - qstart
|
|
338
|
+
d.do_qcheck(newqcheck, qlapse.total_seconds())
|
|
339
|
+
d_next = d.next(ticks=False)
|
|
340
|
+
drets.append(d_next)
|
|
341
|
+
elif data0_direct_load is None:
|
|
342
|
+
for d in datas:
|
|
343
|
+
if has_qcheck:
|
|
344
|
+
d.do_qcheck(False, 0.0)
|
|
345
|
+
d_next = d.next(ticks=False)
|
|
346
|
+
drets.append(d_next)
|
|
347
|
+
# Iterate drets, if d0ret is False and any dret is None, d0ret is None
|
|
348
|
+
if single_data:
|
|
349
|
+
dret0 = drets[0]
|
|
350
|
+
d0ret = bool(dret0)
|
|
351
|
+
if not d0ret and dret0 is None:
|
|
352
|
+
d0ret = None
|
|
353
|
+
else:
|
|
354
|
+
d0ret = any(dret for dret in drets)
|
|
355
|
+
if not d0ret and any(dret is None for dret in drets):
|
|
356
|
+
d0ret = None
|
|
357
|
+
# If d0ret is not None
|
|
358
|
+
if d0ret:
|
|
359
|
+
# Get time
|
|
360
|
+
if single_data:
|
|
361
|
+
try:
|
|
362
|
+
data0_datetime_idx = data0_datetime_line._idx
|
|
363
|
+
if data0_datetime_idx >= 0:
|
|
364
|
+
dt0 = data0_datetime_line.array[data0_datetime_idx]
|
|
365
|
+
else:
|
|
366
|
+
dt0 = data0_datetime_line[0]
|
|
367
|
+
except (AttributeError, IndexError):
|
|
368
|
+
dt0 = data0.datetime[0]
|
|
369
|
+
dts = [dt0]
|
|
370
|
+
dmaster = data0
|
|
371
|
+
else:
|
|
372
|
+
dts = []
|
|
373
|
+
for i, ret in enumerate(drets):
|
|
374
|
+
dts.append(datas[i].datetime[0] if ret else None)
|
|
375
|
+
# Get index to minimum datetime
|
|
376
|
+
# Get minimum time
|
|
377
|
+
if onlyresample or noresample:
|
|
378
|
+
dt0 = min(d for d in dts if d is not None)
|
|
379
|
+
else:
|
|
380
|
+
dt0 = min(
|
|
381
|
+
(d for i, d in enumerate(dts) if d is not None and i not in rsonly)
|
|
382
|
+
)
|
|
383
|
+
# Get master data and time
|
|
384
|
+
dmaster = datas[dts.index(dt0)] # and timemaster
|
|
385
|
+
# Guard: dt0 < 1 means ordinal date before 0001-01-01
|
|
386
|
+
# (invalid/sentinel value from uninitialized data)
|
|
387
|
+
if dt0 < 1:
|
|
388
|
+
logger.warning(
|
|
389
|
+
"Invalid datetime value dt0=%s detected in _runnext, aborting run loop",
|
|
390
|
+
dt0,
|
|
391
|
+
)
|
|
392
|
+
return
|
|
393
|
+
if broker_userhist or broker_fundhist:
|
|
394
|
+
udtmaster = _num2date_cached(dt0)
|
|
395
|
+
self._udtmaster = udtmaster
|
|
396
|
+
self._dtmaster = (
|
|
397
|
+
udtmaster
|
|
398
|
+
if getattr(dmaster, "_tz", None) is None
|
|
399
|
+
else dmaster.num2date(dt0)
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
# Try to get something for those that didn't return
|
|
403
|
+
# Loop through drets
|
|
404
|
+
for i, ret in enumerate(drets):
|
|
405
|
+
# If ret is not None, continue to next ret
|
|
406
|
+
if ret: # dts already contains a valid datetime for this i
|
|
407
|
+
continue
|
|
408
|
+
|
|
409
|
+
# try to get data by checking with a master
|
|
410
|
+
# Get data and try to set time for dts
|
|
411
|
+
d = datas[i]
|
|
412
|
+
d._check(forcedata=dmaster) # check to force output
|
|
413
|
+
if d.next(datamaster=dmaster, ticks=False): # retry
|
|
414
|
+
dts[i] = d.datetime[0] # good -> store
|
|
415
|
+
|
|
416
|
+
# make sure only those at dmaster level end up delivering
|
|
417
|
+
# Iterate dts
|
|
418
|
+
for i, dti in enumerate(dts):
|
|
419
|
+
# If dti is not None
|
|
420
|
+
if dti is not None:
|
|
421
|
+
# Get data
|
|
422
|
+
di = datas[i]
|
|
423
|
+
if dti > dt0:
|
|
424
|
+
di.rewind() # cannot deliver yet
|
|
425
|
+
# If not replay
|
|
426
|
+
elif not di.replaying:
|
|
427
|
+
# Replay forces tick fill, else force here
|
|
428
|
+
try:
|
|
429
|
+
tick_direct_filled = di._tick_direct_filled
|
|
430
|
+
except AttributeError:
|
|
431
|
+
tick_direct_filled = False
|
|
432
|
+
if not tick_direct_filled:
|
|
433
|
+
di._tick_fill(force=True)
|
|
434
|
+
# If d0ret is None, iterate each data and call _check()
|
|
435
|
+
elif d0ret is None:
|
|
436
|
+
# meant for things like live feeds which may not produce a bar
|
|
437
|
+
# at the moment but need the loop to run for notifications and
|
|
438
|
+
# getting resample and others to produce timely bars
|
|
439
|
+
for data in datas:
|
|
440
|
+
data._check()
|
|
441
|
+
# If other case
|
|
442
|
+
else:
|
|
443
|
+
lastret = data0._last()
|
|
444
|
+
for data in datas1:
|
|
445
|
+
lastret += data._last(datamaster=data0)
|
|
446
|
+
if not lastret:
|
|
447
|
+
# Only go extra round if something was changed by "lasts"
|
|
448
|
+
break
|
|
449
|
+
|
|
450
|
+
# Datas may have generated a new notification after next
|
|
451
|
+
# Notify data info
|
|
452
|
+
if not single_default_datanotify or data0.notifs:
|
|
453
|
+
self._datanotify()
|
|
454
|
+
if self._event_stop: # stop if requested
|
|
455
|
+
return
|
|
456
|
+
# Check timer and iterate strategies, call _next_open() to run
|
|
457
|
+
if d0ret or lastret: # if any bar, check timers before broker
|
|
458
|
+
if has_timerscheat:
|
|
459
|
+
self._check_timers(runstrats, dt0, cheat=True)
|
|
460
|
+
if cheat_on_open:
|
|
461
|
+
if single_runstrat is not None:
|
|
462
|
+
single_runstrat_next_open()
|
|
463
|
+
if self._event_stop: # stop if requested
|
|
464
|
+
return
|
|
465
|
+
else:
|
|
466
|
+
for strat in runstrats:
|
|
467
|
+
strat._next_open()
|
|
468
|
+
if self._event_stop: # stop if requested
|
|
469
|
+
return
|
|
470
|
+
# Live brokers can receive fills during a gap in market bars.
|
|
471
|
+
# Bar-matching brokers still require populated data lines.
|
|
472
|
+
poll_without_bar = d0ret is None and broker_next_without_bar
|
|
473
|
+
if d0ret or lastret or poll_without_bar:
|
|
474
|
+
skip_broker_next = False
|
|
475
|
+
if default_backbroker_next:
|
|
476
|
+
skip_broker_next = (
|
|
477
|
+
broker._no_open_positions
|
|
478
|
+
and not broker_pending
|
|
479
|
+
and not broker_submitted
|
|
480
|
+
and not broker_toactivate
|
|
481
|
+
and not broker_userhist
|
|
482
|
+
and not broker_cash_addition
|
|
483
|
+
and not broker_fundhist
|
|
484
|
+
and not broker_dual_side_mode
|
|
485
|
+
and not broker_notifications
|
|
486
|
+
)
|
|
487
|
+
if not skip_broker_next:
|
|
488
|
+
broker_next()
|
|
489
|
+
if default_broker_notifications:
|
|
490
|
+
while broker_notifications:
|
|
491
|
+
order = broker_notifications.popleft()
|
|
492
|
+
owner = order.owner
|
|
493
|
+
if owner is None:
|
|
494
|
+
owner = self.runningstrats[0] # default
|
|
495
|
+
owner._addnotification(order, quicknotify=self.p.quicknotify)
|
|
496
|
+
else:
|
|
497
|
+
while True:
|
|
498
|
+
order = broker_get_notification()
|
|
499
|
+
if order is None:
|
|
500
|
+
break
|
|
501
|
+
owner = order.owner
|
|
502
|
+
if owner is None:
|
|
503
|
+
owner = self.runningstrats[0] # default
|
|
504
|
+
owner._addnotification(order, quicknotify=self.p.quicknotify)
|
|
505
|
+
if poll_without_bar:
|
|
506
|
+
for strat in runstrats:
|
|
507
|
+
if not self.p.quicknotify:
|
|
508
|
+
strat._notify()
|
|
509
|
+
strat.clear()
|
|
510
|
+
if self._event_stop: # stop if requested
|
|
511
|
+
return
|
|
512
|
+
|
|
513
|
+
if d0ret is None:
|
|
514
|
+
for notify_idle in idle_notifiers:
|
|
515
|
+
notify_idle()
|
|
516
|
+
if self._event_stop:
|
|
517
|
+
return
|
|
518
|
+
|
|
519
|
+
# Notify timer and iterate strategies to run
|
|
520
|
+
if d0ret or lastret: # bars produced by data or filters
|
|
521
|
+
if has_timers:
|
|
522
|
+
self._check_timers(runstrats, dt0, cheat=False)
|
|
523
|
+
if single_runstrat is not None:
|
|
524
|
+
single_runstrat_next()
|
|
525
|
+
if self._event_stop: # stop if requested
|
|
526
|
+
return
|
|
527
|
+
|
|
528
|
+
if has_runwriters:
|
|
529
|
+
self._next_writers(runstrats)
|
|
530
|
+
else:
|
|
531
|
+
for strat in runstrats:
|
|
532
|
+
strat._next()
|
|
533
|
+
if self._event_stop: # stop if requested
|
|
534
|
+
return
|
|
535
|
+
|
|
536
|
+
if has_runwriters:
|
|
537
|
+
self._next_writers(runstrats)
|
|
538
|
+
# Last notification chance before stopping
|
|
539
|
+
# Notify data info
|
|
540
|
+
if not single_default_datanotify or data0.notifs:
|
|
541
|
+
self._datanotify()
|
|
542
|
+
if self._event_stop: # stop if requested
|
|
543
|
+
return
|
|
544
|
+
# Notify store info
|
|
545
|
+
if has_stores:
|
|
546
|
+
self._storenotify()
|
|
547
|
+
if self._event_stop: # stop if requested
|
|
548
|
+
return
|
|
549
|
+
except Exception:
|
|
550
|
+
logger.exception("Unhandled exception in _runnext")
|
|
551
|
+
raise
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""Cerebro vectorized engine mixin (iteration 28 split).
|
|
2
|
+
|
|
3
|
+
Moved verbatim from ``backtrader/cerebro.py``: ``_runonce`` (modern) and
|
|
4
|
+
``_runonce_old`` (oldsync).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from ..feed import AbstractDataBase
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RunOnceMixin:
|
|
11
|
+
"""Vectorized engine half of Cerebro (see module docstring)."""
|
|
12
|
+
|
|
13
|
+
# Old runonce method, similar to runonce
|
|
14
|
+
def _runonce_old(self, runstrats):
|
|
15
|
+
"""
|
|
16
|
+
Actual implementation of run in vector mode.
|
|
17
|
+
Strategies are still invoked on a pseudo-event mode in which `next`
|
|
18
|
+
is called for each data arrival
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
for strat in runstrats:
|
|
22
|
+
strat._once()
|
|
23
|
+
|
|
24
|
+
# The default once for strategies does nothing and therefore
|
|
25
|
+
# has not moved forward all datas/indicators/observers that
|
|
26
|
+
# were homed before calling once, Hence no "need" to do it
|
|
27
|
+
# here again, because pointers are at 0
|
|
28
|
+
data0 = self.datas[0]
|
|
29
|
+
datas = self.datas[1:]
|
|
30
|
+
for i in range(data0.buflen()):
|
|
31
|
+
self._storenotify()
|
|
32
|
+
if self._event_stop: # stop if requested
|
|
33
|
+
return
|
|
34
|
+
self._datanotify()
|
|
35
|
+
if self._event_stop: # stop if requested
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
data0.advance()
|
|
39
|
+
for data in datas:
|
|
40
|
+
data.advance(datamaster=data0)
|
|
41
|
+
|
|
42
|
+
self._brokernotify()
|
|
43
|
+
if self._event_stop: # stop if requested
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
for strat in runstrats:
|
|
47
|
+
# data0.datetime[0] for compat. w/ new strategy's oncepost
|
|
48
|
+
strat._oncepost(data0.datetime[0])
|
|
49
|
+
if self._event_stop: # stop if requested
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
self._next_writers(runstrats)
|
|
53
|
+
|
|
54
|
+
self._datanotify()
|
|
55
|
+
if self._event_stop: # stop if requested
|
|
56
|
+
return
|
|
57
|
+
self._storenotify()
|
|
58
|
+
if self._event_stop: # stop if requested
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
# runonce
|
|
62
|
+
def _runonce(self, runstrats):
|
|
63
|
+
"""
|
|
64
|
+
Actual implementation of run in vector mode.
|
|
65
|
+
|
|
66
|
+
Strategies are still invoked on a pseudo-event mode in which `next`
|
|
67
|
+
is called for each data arrival
|
|
68
|
+
"""
|
|
69
|
+
# Iterate strategies, call _once and reset
|
|
70
|
+
for strat in runstrats:
|
|
71
|
+
strat._once()
|
|
72
|
+
strat.reset() # strat called next by next - reset lines
|
|
73
|
+
|
|
74
|
+
# The default once for strategies does nothing and therefore
|
|
75
|
+
# has not moved forward all datas/indicators/observers that
|
|
76
|
+
# were homed before calling once, Hence no "need" to do it
|
|
77
|
+
# here again, because pointers are at 0
|
|
78
|
+
# Sort data from small period to large period
|
|
79
|
+
datas = sorted(self.datas, key=lambda x: (x._timeframe, x._compression))
|
|
80
|
+
data0 = datas[0]
|
|
81
|
+
single_data = len(datas) == 1
|
|
82
|
+
single_default_datanotify = (
|
|
83
|
+
single_data and type(data0).get_notifications is AbstractDataBase.get_notifications
|
|
84
|
+
)
|
|
85
|
+
cheat_on_open = self.p.cheat_on_open
|
|
86
|
+
has_timers = bool(self._timers)
|
|
87
|
+
has_timerscheat = bool(self._timerscheat)
|
|
88
|
+
has_stores = bool(self.stores)
|
|
89
|
+
has_runwriters = bool(self.runwriters)
|
|
90
|
+
|
|
91
|
+
while True:
|
|
92
|
+
if has_stores:
|
|
93
|
+
self._storenotify()
|
|
94
|
+
if self._event_stop: # stop if requested
|
|
95
|
+
return
|
|
96
|
+
if not single_default_datanotify or data0.notifs:
|
|
97
|
+
self._datanotify()
|
|
98
|
+
if self._event_stop: # stop if requested
|
|
99
|
+
return
|
|
100
|
+
|
|
101
|
+
# Check the next incoming date in the datas
|
|
102
|
+
# For each data call advance_peek(), get minimum time as the first one
|
|
103
|
+
dts = [d.advance_peek() for d in datas]
|
|
104
|
+
dt0 = min(dts)
|
|
105
|
+
if dt0 == float("inf"):
|
|
106
|
+
break # no data delivers anything
|
|
107
|
+
|
|
108
|
+
# Timemaster if needed be
|
|
109
|
+
# dmaster = datas[dts.index(dt0)] # and timemaster
|
|
110
|
+
# For each data time, if time <= minimum time, advance data, otherwise ignore
|
|
111
|
+
for i, dti in enumerate(dts):
|
|
112
|
+
if dti <= dt0:
|
|
113
|
+
datas[i].advance()
|
|
114
|
+
# self._plotfillers2[i].append(slen) # mark as fill
|
|
115
|
+
else:
|
|
116
|
+
# self._plotfillers[i].append(slen)
|
|
117
|
+
pass
|
|
118
|
+
# Check timer
|
|
119
|
+
if has_timerscheat:
|
|
120
|
+
self._check_timers(runstrats, dt0, cheat=True)
|
|
121
|
+
# If cheat_on_open, call _oncepost_open() for each strategy
|
|
122
|
+
if cheat_on_open:
|
|
123
|
+
for strat in runstrats:
|
|
124
|
+
strat._oncepost_open()
|
|
125
|
+
# If stop was called, stop
|
|
126
|
+
if self._event_stop: # stop if requested
|
|
127
|
+
return
|
|
128
|
+
# Call _brokernotify()
|
|
129
|
+
self._brokernotify()
|
|
130
|
+
# If stop was called, stop
|
|
131
|
+
if self._event_stop: # stop if requested
|
|
132
|
+
return
|
|
133
|
+
# Check timer
|
|
134
|
+
if has_timers:
|
|
135
|
+
self._check_timers(runstrats, dt0, cheat=False)
|
|
136
|
+
|
|
137
|
+
for strat in runstrats:
|
|
138
|
+
strat._oncepost(dt0)
|
|
139
|
+
if self._event_stop: # stop if requested
|
|
140
|
+
return
|
|
141
|
+
if has_runwriters:
|
|
142
|
+
self._next_writers(runstrats)
|