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
backtrader/tradingcal.py
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Trading Calendar Module - Market calendar and session handling.
|
|
3
|
+
|
|
4
|
+
This module provides trading calendar functionality for handling market
|
|
5
|
+
sessions, holidays, and trading days. It supports custom calendars
|
|
6
|
+
and pandas market calendar integration.
|
|
7
|
+
|
|
8
|
+
Classes:
|
|
9
|
+
TradingCalendarBase: Base class for trading calendars.
|
|
10
|
+
TradingCalendar: Standard trading calendar implementation.
|
|
11
|
+
PandasMarketCalendar: Wrapper for pandas_market_cal calendars.
|
|
12
|
+
|
|
13
|
+
Constants:
|
|
14
|
+
MONDAY-SUNDAY: Weekday constants.
|
|
15
|
+
WEEKEND: Weekend days (Saturday, Sunday).
|
|
16
|
+
ONEDAY: Timedelta of one day.
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
Using a trading calendar:
|
|
20
|
+
>>> cal = bt.TradingCalendar()
|
|
21
|
+
>>> next_day = cal.nextday(datetime.date(2020, 1, 1))
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from datetime import datetime, time, timedelta
|
|
25
|
+
|
|
26
|
+
from backtrader.utils import UTC
|
|
27
|
+
from backtrader.utils.py3 import string_types
|
|
28
|
+
|
|
29
|
+
from .parameters import ParameterizedBase
|
|
30
|
+
|
|
31
|
+
# All classes that can be imported via "from tradingcal import *"
|
|
32
|
+
__all__ = ["TradingCalendarBase", "TradingCalendar", "PandasMarketCalendar"]
|
|
33
|
+
|
|
34
|
+
# Imprecision in the full time conversion to float would wrap over to next day
|
|
35
|
+
# if microseconds are 999,999 as defined in time.max
|
|
36
|
+
# Maximum time of the day
|
|
37
|
+
_time_max = time(hour=23, minute=59, second=59, microsecond=999990)
|
|
38
|
+
|
|
39
|
+
# Constants for seven days of the week, Monday is 0, Sunday is 6
|
|
40
|
+
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY = range(7)
|
|
41
|
+
# Determine day of week, no date is 0, Monday is 1, Sunday is 7
|
|
42
|
+
ISONODAY, ISOMONDAY, ISOTUESDAY, ISOWEDNESDAY, ISOTHURSDAY, ISOFRIDAY, ISOSATURDAY, ISOSUNDAY = (
|
|
43
|
+
range(8)
|
|
44
|
+
)
|
|
45
|
+
# Weekend is Saturday and Sunday
|
|
46
|
+
WEEKEND = [SATURDAY, SUNDAY]
|
|
47
|
+
# Whether it is weekend
|
|
48
|
+
ISOWEEKEND = [ISOSATURDAY, ISOSUNDAY]
|
|
49
|
+
# Time difference of one day
|
|
50
|
+
ONEDAY = timedelta(days=1)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Trading calendar base class, defines specific methods - refactored to not use metaclass
|
|
54
|
+
class TradingCalendarBase(ParameterizedBase):
|
|
55
|
+
"""Base class for trading calendars.
|
|
56
|
+
|
|
57
|
+
Provides methods for calculating trading days, session times,
|
|
58
|
+
and determining if a day is the last trading day of a week or month.
|
|
59
|
+
|
|
60
|
+
Methods:
|
|
61
|
+
_nextday(day): Returns next trading day and isocalendar components.
|
|
62
|
+
schedule(day): Returns opening and closing times for a day.
|
|
63
|
+
nextday(day): Returns next trading day.
|
|
64
|
+
last_weekday(day): Returns True if day is last trading day of week.
|
|
65
|
+
last_monthday(day): Returns True if day is last trading day of month.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
# Return the next trading day after day and calendar composition
|
|
69
|
+
def _nextday(self, day):
|
|
70
|
+
"""
|
|
71
|
+
Returns the next trading day (datetime/date instance) after ``day``
|
|
72
|
+
(datetime/date instance) and the isocalendar components
|
|
73
|
+
|
|
74
|
+
The return value is a tuple with two parts: (nextday, (y, w, d))
|
|
75
|
+
"""
|
|
76
|
+
raise NotImplementedError
|
|
77
|
+
|
|
78
|
+
# Return opening and closing times of a day
|
|
79
|
+
def schedule(self, day):
|
|
80
|
+
"""
|
|
81
|
+
Returns a tuple with the opening and closing times (``datetime.time``)
|
|
82
|
+
for the given ``date`` (``datetime/date`` instance)
|
|
83
|
+
"""
|
|
84
|
+
raise NotImplementedError
|
|
85
|
+
|
|
86
|
+
# Return the next trading day after day
|
|
87
|
+
def nextday(self, day):
|
|
88
|
+
"""
|
|
89
|
+
Returns the next trading day (datetime/date instance) after ``day``
|
|
90
|
+
(datetime/date instance)
|
|
91
|
+
"""
|
|
92
|
+
return self._nextday(day)[0] # 1st ret elem is next day
|
|
93
|
+
|
|
94
|
+
# Return the week number of the next trading day after day
|
|
95
|
+
def nextday_week(self, day):
|
|
96
|
+
"""
|
|
97
|
+
Returns the iso week number of the next trading day, given a ``day``
|
|
98
|
+
(datetime/date) instance
|
|
99
|
+
"""
|
|
100
|
+
return self._nextday(day)[1][1] # 2 elem is isocal / 0 - y, 1 - wk, 2 - day
|
|
101
|
+
|
|
102
|
+
# Calculate if the current day is the last day of this week
|
|
103
|
+
def last_weekday(self, day):
|
|
104
|
+
"""
|
|
105
|
+
Returns ``True`` if the given ``day`` (datetime/date) instance is the
|
|
106
|
+
last trading day of this week
|
|
107
|
+
"""
|
|
108
|
+
# Next day must be greater than day.
|
|
109
|
+
# If the week changes are enough for
|
|
110
|
+
# a week change even if the number is smaller (year change)
|
|
111
|
+
return day.isocalendar()[1] != self._nextday(day)[1][1]
|
|
112
|
+
|
|
113
|
+
# Determine if the current day is the last day of this month
|
|
114
|
+
def last_monthday(self, day):
|
|
115
|
+
"""
|
|
116
|
+
Returns ``True`` if the given ``day`` (datetime/date) instance is the
|
|
117
|
+
last trading day of this month
|
|
118
|
+
"""
|
|
119
|
+
# Next day must be greater than day.
|
|
120
|
+
# If the week changes are enough for
|
|
121
|
+
# a week change even if the number is smaller (year change)
|
|
122
|
+
return day.month != self._nextday(day)[0].month
|
|
123
|
+
|
|
124
|
+
# Determine if the current day is the last day of this year
|
|
125
|
+
def last_yearday(self, day):
|
|
126
|
+
"""
|
|
127
|
+
Returns ``True`` if the given ``day`` (datetime/date) instance is the
|
|
128
|
+
last trading day of this month
|
|
129
|
+
"""
|
|
130
|
+
# Next day must be greater than day.
|
|
131
|
+
# If the week changes are enough for
|
|
132
|
+
# a week change even if the number is smaller (year change)
|
|
133
|
+
return day.year != self._nextday(day)[0].year
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# Trading calendar class - refactored to not use metaclass
|
|
137
|
+
class TradingCalendar(TradingCalendarBase):
|
|
138
|
+
"""
|
|
139
|
+
Wrapper of ``pandas_market_calendars`` for a trading calendar. The package
|
|
140
|
+
``pandas_market_calendar`` must be installed
|
|
141
|
+
# In this class, it seems that pandas_market_calendar is not strictly required
|
|
142
|
+
Params:
|
|
143
|
+
|
|
144
|
+
- ``open`` (default ``time.min``)
|
|
145
|
+
|
|
146
|
+
Regular start of the session
|
|
147
|
+
|
|
148
|
+
# open, trading day start time, default is minimum time
|
|
149
|
+
|
|
150
|
+
- ``close`` (default ``time.max``)
|
|
151
|
+
|
|
152
|
+
Regular end of the session
|
|
153
|
+
# close, trading day end time, default is maximum time
|
|
154
|
+
|
|
155
|
+
- ``holidays`` (default ``[]``)
|
|
156
|
+
|
|
157
|
+
List of non-trading days (``datetime.datetime`` instances)
|
|
158
|
+
|
|
159
|
+
# holidays, holidays, list of datetime times
|
|
160
|
+
|
|
161
|
+
- ``earlydays`` (default ``[]``)
|
|
162
|
+
|
|
163
|
+
List of tuples determining the date and opening/closing times of days
|
|
164
|
+
which do not conform to the regular trading hours when each tuple has
|
|
165
|
+
(``datetime.datetime``, ``datetime.time``, ``datetime.time``)
|
|
166
|
+
# earlydays, trading days with non-standard trading start and end times
|
|
167
|
+
|
|
168
|
+
- ``offdays`` (default ``ISOWEEKEND``)
|
|
169
|
+
|
|
170
|
+
A list of weekdays in ISO format (Monday: 1 -> Sunday: 7) in which the
|
|
171
|
+
market doesn't trade. This is usually Saturday and Sunday and hence the
|
|
172
|
+
default
|
|
173
|
+
|
|
174
|
+
# offdays, non-trading dates from Monday to Sunday, usually Saturday and Sunday
|
|
175
|
+
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
# Parameters
|
|
179
|
+
params: tuple = (
|
|
180
|
+
("open", time.min),
|
|
181
|
+
("close", _time_max),
|
|
182
|
+
("holidays", []), # list of non-trading days (date)
|
|
183
|
+
("earlydays", []), # list of tuples (date, opentime, closetime)
|
|
184
|
+
("offdays", ISOWEEKEND), # list of non-trading (isoweekdays)
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Initialize, get these dates based on earlydays to speed up searches
|
|
188
|
+
def __init__(self, **kwargs):
|
|
189
|
+
"""Initialize the TradingCalendar.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
**kwargs: Keyword arguments for calendar parameters.
|
|
193
|
+
"""
|
|
194
|
+
super().__init__(**kwargs)
|
|
195
|
+
self._earlydays = [x[0] for x in self.p.earlydays] # speed up searches
|
|
196
|
+
|
|
197
|
+
# Get the next trading day
|
|
198
|
+
def _nextday(self, day):
|
|
199
|
+
"""
|
|
200
|
+
Returns the next trading day (datetime/date instance) after ``day``
|
|
201
|
+
(datetime/date instance) and the isocalendar components
|
|
202
|
+
|
|
203
|
+
The return value is a tuple with two parts: (nextday, (y, w, d))
|
|
204
|
+
"""
|
|
205
|
+
# while loop
|
|
206
|
+
while True:
|
|
207
|
+
# Next trading day
|
|
208
|
+
day += ONEDAY
|
|
209
|
+
# Get calendar information of day
|
|
210
|
+
isocal = day.isocalendar()
|
|
211
|
+
# If day is Saturday, Sunday or a holiday, continue loop to get next day
|
|
212
|
+
if isocal[2] in self.p.offdays or day in self.p.holidays:
|
|
213
|
+
continue
|
|
214
|
+
# If day is not Saturday, Sunday or holiday, day is the desired next trading day
|
|
215
|
+
return day, isocal
|
|
216
|
+
|
|
217
|
+
# Get opening and closing times of day
|
|
218
|
+
def schedule(self, day, tz=None):
|
|
219
|
+
"""
|
|
220
|
+
Returns the opening and closing times for the given ``day``. If the
|
|
221
|
+
method is called, the assumption is that `day` is an actual trading
|
|
222
|
+
day
|
|
223
|
+
|
|
224
|
+
The return value is a tuple with 2 components: opentime, closetime
|
|
225
|
+
"""
|
|
226
|
+
# while loop
|
|
227
|
+
while True:
|
|
228
|
+
# Get date of day
|
|
229
|
+
dt = day.date()
|
|
230
|
+
# Try to get if trading day is in earlydays, if so, get specific opening and closing times
|
|
231
|
+
# If not, opening defaults to current minimum time, closing defaults to maximum time of the day
|
|
232
|
+
try:
|
|
233
|
+
i = self._earlydays.index(dt)
|
|
234
|
+
o, c = self.p.earlydays[i][1:]
|
|
235
|
+
except ValueError: # not found
|
|
236
|
+
o, c = self.p.open, self.p.close
|
|
237
|
+
# Combine closing date and time
|
|
238
|
+
closing = datetime.combine(dt, c)
|
|
239
|
+
# If timezone is not None, convert closing time according to timezone
|
|
240
|
+
if tz is not None:
|
|
241
|
+
closing = tz.localize(closing).astimezone(UTC)
|
|
242
|
+
closing = closing.replace(tzinfo=None)
|
|
243
|
+
# If day is greater than closing time, skip to next trading day and restart loop
|
|
244
|
+
if day > closing: # current time over eos
|
|
245
|
+
day += ONEDAY
|
|
246
|
+
continue
|
|
247
|
+
# Opening date and time
|
|
248
|
+
opening = datetime.combine(dt, o)
|
|
249
|
+
# If timezone is not None, convert closing time according to timezone
|
|
250
|
+
if tz is not None:
|
|
251
|
+
opening = tz.localize(opening).astimezone(UTC)
|
|
252
|
+
opening = opening.replace(tzinfo=None)
|
|
253
|
+
|
|
254
|
+
return opening, closing
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class PandasMarketCalendar(TradingCalendarBase):
|
|
258
|
+
"""
|
|
259
|
+
Wrapper of ``pandas_market_calendars`` for a trading calendar. The package
|
|
260
|
+
``pandas_market_calendar`` must be installed
|
|
261
|
+
# pandas_market_calendar must be installed
|
|
262
|
+
Params:
|
|
263
|
+
|
|
264
|
+
- ``calendar`` (default ``None``)
|
|
265
|
+
|
|
266
|
+
The param ``calendar`` accepts the following:
|
|
267
|
+
|
|
268
|
+
- string: the name of one of the calendars supported, for example,
|
|
269
|
+
`NYSE`. The wrapper will attempt to get a calendar instance
|
|
270
|
+
|
|
271
|
+
- Calendar instance: as returned by ``get_calendar('NYSE')``
|
|
272
|
+
|
|
273
|
+
# calendar information, can be string or calendar instance
|
|
274
|
+
|
|
275
|
+
- ``cachesize`` (default ``365``)
|
|
276
|
+
|
|
277
|
+
Number of days to cache in advance for lookup
|
|
278
|
+
|
|
279
|
+
# How many dates to cache in advance for convenient lookup
|
|
280
|
+
|
|
281
|
+
See also:
|
|
282
|
+
|
|
283
|
+
- https://github.com/rsheftel/pandas_market_calendars
|
|
284
|
+
|
|
285
|
+
- http://pandas-market-calendars.readthedocs.io/
|
|
286
|
+
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
# Parameters
|
|
290
|
+
params = (
|
|
291
|
+
("calendar", None), # A pandas_market_calendars instance or exch name
|
|
292
|
+
("cachesize", 365), # Number of days to cache in advance
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
# Initialize
|
|
296
|
+
def __init__(self, **kwargs):
|
|
297
|
+
"""Initialize the PandasMarketCalendar.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
**kwargs: Keyword arguments for calendar parameters.
|
|
301
|
+
"""
|
|
302
|
+
super().__init__(**kwargs)
|
|
303
|
+
self._calendar = self.p.calendar
|
|
304
|
+
# If self._calendar is a string, use get_calendar to convert to calendar instance
|
|
305
|
+
if isinstance(self._calendar, string_types): # use passed mkt name
|
|
306
|
+
import pandas_market_calendars as mcal
|
|
307
|
+
|
|
308
|
+
self._calendar = mcal.get_calendar(self._calendar)
|
|
309
|
+
# Create self.dcache, self.idcache, self.csize
|
|
310
|
+
import pandas as pd # guaranteed because of pandas_market_calendars
|
|
311
|
+
|
|
312
|
+
self.dcache = pd.DatetimeIndex([0.0])
|
|
313
|
+
self.idcache = pd.DataFrame(index=pd.DatetimeIndex([0.0]))
|
|
314
|
+
self.csize = timedelta(days=self.p.cachesize)
|
|
315
|
+
|
|
316
|
+
# Get the next trading day
|
|
317
|
+
def _nextday(self, day):
|
|
318
|
+
"""
|
|
319
|
+
Returns the next trading day (datetime/date instance) after ``day``
|
|
320
|
+
(datetime/date instance) and the isocalendar components
|
|
321
|
+
|
|
322
|
+
The return value is a tuple with two parts: (nextday, (y, w, d))
|
|
323
|
+
"""
|
|
324
|
+
day += ONEDAY
|
|
325
|
+
while True:
|
|
326
|
+
# Get the index where day is located
|
|
327
|
+
i = self.dcache.searchsorted(day)
|
|
328
|
+
# If index equals self.dcache length, dates have been used up and need to be updated
|
|
329
|
+
if i == len(self.dcache):
|
|
330
|
+
# keep a cache of 1 year to speed up searching
|
|
331
|
+
self.dcache = self._calendar.valid_days(day, day + self.csize)
|
|
332
|
+
continue
|
|
333
|
+
# If can get the index where day is located from self.dcache, then convert to time
|
|
334
|
+
d = self.dcache[i].to_pydatetime()
|
|
335
|
+
return d, d.isocalendar()
|
|
336
|
+
|
|
337
|
+
# Get specific opening and closing times
|
|
338
|
+
def schedule(self, day, tz=None):
|
|
339
|
+
"""
|
|
340
|
+
Returns the opening and closing times for the given ``day``. If the
|
|
341
|
+
method is called, the assumption is that `day` is an actual trading
|
|
342
|
+
day
|
|
343
|
+
|
|
344
|
+
The return value is a tuple with 2 components: opentime, closetime
|
|
345
|
+
"""
|
|
346
|
+
while True:
|
|
347
|
+
# Get the index where trading day is located, then determine if calendar data needs to be updated
|
|
348
|
+
i = self.idcache.index.searchsorted(day.date())
|
|
349
|
+
if i == len(self.idcache):
|
|
350
|
+
# keep a cache of 1 year to speed up searching
|
|
351
|
+
self.idcache = self._calendar.schedule(day, day + self.csize)
|
|
352
|
+
continue
|
|
353
|
+
# Convert calendar information to generate tuple of opening and closing times
|
|
354
|
+
st = (x.tz_localize(None) for x in self.idcache.iloc[i, 0:2])
|
|
355
|
+
opening, closing = st # Get utc naive times
|
|
356
|
+
# If current day is already greater than closing time, skip to next day, update latest opening and closing times, then return
|
|
357
|
+
if day > closing: # passed time is over the sessionend
|
|
358
|
+
day += ONEDAY # wrap over to next day
|
|
359
|
+
continue
|
|
360
|
+
|
|
361
|
+
return opening.to_pydatetime(), closing.to_pydatetime()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Utilities Module - Common utility functions and classes.
|
|
3
|
+
|
|
4
|
+
This module provides common utilities used throughout the backtrader framework
|
|
5
|
+
including data structures, date/time conversions, and helper functions.
|
|
6
|
+
|
|
7
|
+
Exports:
|
|
8
|
+
AutoDict, AutoDictList, AutoOrderedDict, DotDict: Dictionary utilities.
|
|
9
|
+
OrderedDict: Ordered dictionary from collections.
|
|
10
|
+
num2date, date2num, num2dt, num2time, time2num: Date/time conversions.
|
|
11
|
+
tzparse, Localizer, TIME_MAX: Timezone utilities.
|
|
12
|
+
|
|
13
|
+
Example:
|
|
14
|
+
>>> from backtrader.utils import OrderedDict, date2num
|
|
15
|
+
>>> od = OrderedDict()
|
|
16
|
+
>>> od['key'] = 'value'
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from collections import OrderedDict as OrderedDict
|
|
20
|
+
|
|
21
|
+
from .autodict import AutoDict as AutoDict
|
|
22
|
+
from .autodict import AutoDictList as AutoDictList
|
|
23
|
+
from .autodict import AutoOrderedDict as AutoOrderedDict
|
|
24
|
+
from .autodict import DotDict as DotDict
|
|
25
|
+
from .dateintern import TIME_MAX as TIME_MAX
|
|
26
|
+
from .dateintern import UTC as UTC
|
|
27
|
+
from .dateintern import Localizer as Localizer
|
|
28
|
+
from .dateintern import TZLocal as TZLocal
|
|
29
|
+
from .dateintern import date2num as date2num
|
|
30
|
+
from .dateintern import num2date as num2date
|
|
31
|
+
from .dateintern import num2dt as num2dt
|
|
32
|
+
from .dateintern import num2time as num2time
|
|
33
|
+
from .dateintern import time2num as time2num
|
|
34
|
+
from .dateintern import tzparse as tzparse
|
|
35
|
+
from .get_metrics import STANDARD_METRIC_FIELDS as STANDARD_METRIC_FIELDS
|
|
36
|
+
from .get_metrics import extract_backtest_metrics as extract_backtest_metrics
|
|
37
|
+
from .get_metrics import get_backtest_metrics as get_backtest_metrics
|
|
38
|
+
from .get_metrics import write_metrics as write_metrics
|
|
39
|
+
from .log_message import configure_logging as configure_logging
|
|
40
|
+
from .log_message import get_logger as get_logger
|
|
41
|
+
from .log_message import reset_logging as reset_logging
|
|
42
|
+
from .log_message import set_level as set_level
|
|
43
|
+
|
|
44
|
+
__all__ = [
|
|
45
|
+
"OrderedDict",
|
|
46
|
+
"AutoDict",
|
|
47
|
+
"AutoDictList",
|
|
48
|
+
"AutoOrderedDict",
|
|
49
|
+
"DotDict",
|
|
50
|
+
"TIME_MAX",
|
|
51
|
+
"UTC",
|
|
52
|
+
"Localizer",
|
|
53
|
+
"TZLocal",
|
|
54
|
+
"date2num",
|
|
55
|
+
"num2date",
|
|
56
|
+
"num2dt",
|
|
57
|
+
"num2time",
|
|
58
|
+
"time2num",
|
|
59
|
+
"tzparse",
|
|
60
|
+
"STANDARD_METRIC_FIELDS",
|
|
61
|
+
"get_backtest_metrics",
|
|
62
|
+
"extract_backtest_metrics",
|
|
63
|
+
"write_metrics",
|
|
64
|
+
"get_logger",
|
|
65
|
+
"configure_logging",
|
|
66
|
+
"set_level",
|
|
67
|
+
"reset_logging",
|
|
68
|
+
]
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""AutoDict Module - Enhanced dictionary classes.
|
|
3
|
+
|
|
4
|
+
This module provides dictionary subclasses with automatic key creation,
|
|
5
|
+
dot notation access, and ordered dict support.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
AutoDict: Dict with automatic nested dict creation.
|
|
9
|
+
AutoOrderedDict: OrderedDict with automatic nested dict creation.
|
|
10
|
+
DotDict: Dict with attribute-style access (obj.key).
|
|
11
|
+
AutoDictList: Dict with automatic list creation for missing keys.
|
|
12
|
+
|
|
13
|
+
Example:
|
|
14
|
+
>>> d = AutoOrderedDict()
|
|
15
|
+
>>> d['a']['b']['c'] = 1 # Automatically creates nested dicts
|
|
16
|
+
>>> print(d['a']['b']['c'])
|
|
17
|
+
1
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from collections import OrderedDict, defaultdict
|
|
21
|
+
|
|
22
|
+
from ..utils.log_message import get_logger
|
|
23
|
+
from .py3 import values as py3lvalues
|
|
24
|
+
|
|
25
|
+
logger = get_logger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def Tree():
|
|
29
|
+
"""Create a recursive defaultdict structure.
|
|
30
|
+
|
|
31
|
+
Returns a defaultdict that automatically creates nested defaultdicts
|
|
32
|
+
for any missing key, allowing for infinite nesting.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
defaultdict: A recursive defaultdict structure.
|
|
36
|
+
"""
|
|
37
|
+
return defaultdict(Tree)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class AutoDictList(dict):
|
|
41
|
+
"""Dictionary that creates an empty list for missing keys.
|
|
42
|
+
|
|
43
|
+
When accessing a key that doesn't exist, automatically creates
|
|
44
|
+
a new empty list for that key.
|
|
45
|
+
|
|
46
|
+
Example:
|
|
47
|
+
>>> d = AutoDictList()
|
|
48
|
+
>>> d['key'].append('value')
|
|
49
|
+
>>> print(d['key'])
|
|
50
|
+
['value']
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
# Inherits dict, when accessing missing key, will automatically generate a key value, corresponding value is an empty list
|
|
54
|
+
# This newly created class is only used in collections.defaultdict(AutoDictList) line
|
|
55
|
+
def __missing__(self, key):
|
|
56
|
+
value = self[key] = []
|
|
57
|
+
return value
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class DotDict(dict):
|
|
61
|
+
"""Dictionary with attribute-style access.
|
|
62
|
+
|
|
63
|
+
Allows accessing dictionary values as attributes using dot notation.
|
|
64
|
+
If an attribute is not found in the usual places, the dict itself
|
|
65
|
+
is checked.
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
>>> d = DotDict()
|
|
69
|
+
>>> d['key'] = 'value'
|
|
70
|
+
>>> print(d.key)
|
|
71
|
+
'value'
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
# If the attribute is not found in the usual places, try the dict itself
|
|
75
|
+
# This class is only used in the following line, when accessing attributes, if attribute doesn't exist, __getattr__ will be called
|
|
76
|
+
# _obj.dnames = DotDict([(d._name, d) for d in _obj.datas if getattr(d, '_name', '')])
|
|
77
|
+
def __getattr__(self, key):
|
|
78
|
+
if key.startswith("__"):
|
|
79
|
+
# return super().__getattr__(key)
|
|
80
|
+
raise AttributeError(key)
|
|
81
|
+
return self[key]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# This function has slightly wider usage, mainly called in tradeanalyzer and ibstore, is an extension of Python dict
|
|
85
|
+
# Compared to Python built-in dict, added an attribute: _closed, added functions _close, _open, __missing__, __getattr__, overrode __setattr__
|
|
86
|
+
class AutoDict(dict):
|
|
87
|
+
"""Dictionary with automatic nested dict creation and closeable state.
|
|
88
|
+
|
|
89
|
+
Extends dict with:
|
|
90
|
+
- Automatic nested dict creation for missing keys
|
|
91
|
+
- Closeable state (_closed) to prevent further auto-creation
|
|
92
|
+
- Attribute-style access
|
|
93
|
+
|
|
94
|
+
Attributes:
|
|
95
|
+
_closed: If True, __missing__ raises KeyError instead of creating nested dicts.
|
|
96
|
+
|
|
97
|
+
Methods:
|
|
98
|
+
_close(): Set _closed to True to prevent auto-creation.
|
|
99
|
+
_open(): Set _closed to False to enable auto-creation.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
# Initialize default attribute _closed to False
|
|
103
|
+
_closed = False
|
|
104
|
+
|
|
105
|
+
# _close method
|
|
106
|
+
def _close(self):
|
|
107
|
+
# Change class attribute to True
|
|
108
|
+
self._closed = True
|
|
109
|
+
# For values in dict, if they are instances of AutoDict or AutoOrderedDict, call _close method to set attribute _closed to True
|
|
110
|
+
for key, val in self.items():
|
|
111
|
+
if isinstance(val, (AutoDict, AutoOrderedDict)):
|
|
112
|
+
val._close()
|
|
113
|
+
|
|
114
|
+
# _open method, set _closed attribute to False
|
|
115
|
+
def _open(self):
|
|
116
|
+
self._closed = False
|
|
117
|
+
for key, val in self.items():
|
|
118
|
+
if isinstance(val, (AutoDict, AutoOrderedDict)):
|
|
119
|
+
val._open()
|
|
120
|
+
|
|
121
|
+
# __missing__ method handles case when key doesn't exist, if _closed, return KeyError, if not, create an AutoDict() instance for this key
|
|
122
|
+
def __missing__(self, key):
|
|
123
|
+
if self._closed:
|
|
124
|
+
raise KeyError(key)
|
|
125
|
+
|
|
126
|
+
value = self[key] = AutoDict()
|
|
127
|
+
return value
|
|
128
|
+
|
|
129
|
+
def __getattr__(self, key):
|
|
130
|
+
if key.startswith("_"):
|
|
131
|
+
raise AttributeError(key)
|
|
132
|
+
try:
|
|
133
|
+
return self[key]
|
|
134
|
+
except KeyError:
|
|
135
|
+
logger.debug("autodict: key not found, re-raising KeyError")
|
|
136
|
+
raise AttributeError(key) from None
|
|
137
|
+
|
|
138
|
+
def __setattr__(self, key, value):
|
|
139
|
+
if key.startswith("_"):
|
|
140
|
+
self.__dict__[key] = value
|
|
141
|
+
return
|
|
142
|
+
self[key] = value
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# Created a new ordered dict, added some functions, similar to AutoDict
|
|
146
|
+
class AutoOrderedDict(OrderedDict):
|
|
147
|
+
"""OrderedDict with automatic nested dict creation and closeable state.
|
|
148
|
+
|
|
149
|
+
Combines OrderedDict's insertion ordering with AutoDict's automatic
|
|
150
|
+
nested dict creation and closeable state.
|
|
151
|
+
|
|
152
|
+
Attributes:
|
|
153
|
+
_closed: If True, __missing__ raises KeyError instead of creating nested dicts.
|
|
154
|
+
|
|
155
|
+
Methods:
|
|
156
|
+
_close(): Set _closed to True to prevent auto-creation.
|
|
157
|
+
_open(): Set _closed to False to enable auto-creation.
|
|
158
|
+
|
|
159
|
+
Example:
|
|
160
|
+
>>> d = AutoOrderedDict()
|
|
161
|
+
>>> d['a']['b'] = 1 # Automatically creates nested dicts
|
|
162
|
+
>>> d._close() # Prevent further auto-creation
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
_closed = False
|
|
166
|
+
|
|
167
|
+
def _close(self):
|
|
168
|
+
self._closed = True
|
|
169
|
+
for key, val in self.items():
|
|
170
|
+
if isinstance(val, (AutoDict, AutoOrderedDict)):
|
|
171
|
+
val._close()
|
|
172
|
+
|
|
173
|
+
def _open(self):
|
|
174
|
+
self._closed = False
|
|
175
|
+
for key, val in self.items():
|
|
176
|
+
if isinstance(val, (AutoDict, AutoOrderedDict)):
|
|
177
|
+
val._open()
|
|
178
|
+
|
|
179
|
+
def __missing__(self, key):
|
|
180
|
+
if self._closed:
|
|
181
|
+
raise KeyError(key)
|
|
182
|
+
|
|
183
|
+
# value = self[key] = type(self)()
|
|
184
|
+
value = self[key] = AutoOrderedDict()
|
|
185
|
+
return value
|
|
186
|
+
|
|
187
|
+
# __getattr__ and __setattr__ functions are much more normal compared to AutoDict
|
|
188
|
+
def __getattr__(self, key):
|
|
189
|
+
if key.startswith("_"):
|
|
190
|
+
raise AttributeError(key)
|
|
191
|
+
try:
|
|
192
|
+
return self[key]
|
|
193
|
+
except KeyError:
|
|
194
|
+
logger.debug("autodict: attribute miss, re-raising KeyError")
|
|
195
|
+
raise AttributeError(key) from None
|
|
196
|
+
|
|
197
|
+
def __setattr__(self, key, value):
|
|
198
|
+
if key.startswith("_"):
|
|
199
|
+
self.__dict__[key] = value
|
|
200
|
+
return
|
|
201
|
+
|
|
202
|
+
self[key] = value
|
|
203
|
+
|
|
204
|
+
# Defined math operations, not sure what they mean for now, but it seems only __iadd__ and __isub__ are normal
|
|
205
|
+
# Define math operations
|
|
206
|
+
def __iadd__(self, other):
|
|
207
|
+
if not isinstance(other, type(self)):
|
|
208
|
+
return type(other)() + other
|
|
209
|
+
|
|
210
|
+
return self + other
|
|
211
|
+
|
|
212
|
+
def __isub__(self, other):
|
|
213
|
+
if not isinstance(other, type(self)):
|
|
214
|
+
return type(other)() - other
|
|
215
|
+
|
|
216
|
+
return self - other
|
|
217
|
+
|
|
218
|
+
def __imul__(self, other):
|
|
219
|
+
if not isinstance(other, type(self)):
|
|
220
|
+
return type(other)() * other
|
|
221
|
+
|
|
222
|
+
return self * other
|
|
223
|
+
|
|
224
|
+
def __idiv__(self, other):
|
|
225
|
+
if not isinstance(other, type(self)):
|
|
226
|
+
return type(other)() // other
|
|
227
|
+
|
|
228
|
+
return self // other
|
|
229
|
+
|
|
230
|
+
def __itruediv__(self, other):
|
|
231
|
+
if not isinstance(other, type(self)):
|
|
232
|
+
return type(other)() / other
|
|
233
|
+
|
|
234
|
+
return self / other
|
|
235
|
+
|
|
236
|
+
def lvalues(self):
|
|
237
|
+
"""Return dictionary values as a list.
|
|
238
|
+
|
|
239
|
+
Provides Python 2/3 compatible list of values.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
list: List of all values in the dictionary.
|
|
243
|
+
"""
|
|
244
|
+
return py3lvalues(self)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
if __name__ == "__main__":
|
|
248
|
+
aod = AutoOrderedDict()
|
|
249
|
+
print("aod", dir(aod))
|
|
250
|
+
od: dict = OrderedDict()
|
|
251
|
+
print("od", dir(od))
|