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,203 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Backtrader CSV Data Feed Module - Test CSV format.
|
|
3
|
+
|
|
4
|
+
This module provides the BacktraderCSVData feed for parsing
|
|
5
|
+
a custom CSV format used for testing.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
BacktraderCSVData: Parses backtrader test CSV format.
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
>>> data = bt.feeds.BacktraderCSVData(dataname='test.csv')
|
|
12
|
+
>>> cerebro.adddata(data)
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import math
|
|
16
|
+
from datetime import date
|
|
17
|
+
|
|
18
|
+
from .. import feed
|
|
19
|
+
from ..utils.log_message import get_logger
|
|
20
|
+
|
|
21
|
+
logger = get_logger(__name__)
|
|
22
|
+
|
|
23
|
+
_HOURS_PER_DAY = 24.0
|
|
24
|
+
_MINUTES_PER_DAY = 1440.0
|
|
25
|
+
_SECONDS_PER_DAY = 86400.0
|
|
26
|
+
_MICROSECONDS_PER_DAY = 86400000000.0
|
|
27
|
+
_INF = float("inf")
|
|
28
|
+
_NEG_INF = float("-inf")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _set_current_value(line, value):
|
|
32
|
+
"""Set the current line slot, falling back when binding propagation is needed."""
|
|
33
|
+
if value in (_INF, _NEG_INF):
|
|
34
|
+
value = line._default_value
|
|
35
|
+
|
|
36
|
+
if line.bindings:
|
|
37
|
+
line[0] = value
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
idx = line._idx
|
|
41
|
+
if idx < 0:
|
|
42
|
+
line[0] = value
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
line.array[idx] = value
|
|
47
|
+
except IndexError:
|
|
48
|
+
line[0] = value
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class BacktraderCSVData(feed.CSVDataBase):
|
|
52
|
+
"""
|
|
53
|
+
Parses a self-defined CSV Data used for testing.
|
|
54
|
+
|
|
55
|
+
Specific parameters:
|
|
56
|
+
|
|
57
|
+
- ``dataname``: The filename to parse or a file-like object
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def _loadline(self, linetokens):
|
|
61
|
+
"""Parse a line from the CSV file.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
linetokens: List of tokenized CSV values.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
True if line was successfully parsed.
|
|
68
|
+
"""
|
|
69
|
+
try:
|
|
70
|
+
(
|
|
71
|
+
line_datetime,
|
|
72
|
+
line_open,
|
|
73
|
+
line_high,
|
|
74
|
+
line_low,
|
|
75
|
+
line_close,
|
|
76
|
+
line_volume,
|
|
77
|
+
line_openinterest,
|
|
78
|
+
) = self._btcsv_line_refs
|
|
79
|
+
except AttributeError:
|
|
80
|
+
lines = self.lines
|
|
81
|
+
line_datetime = lines.datetime
|
|
82
|
+
line_open = lines.open
|
|
83
|
+
line_high = lines.high
|
|
84
|
+
line_low = lines.low
|
|
85
|
+
line_close = lines.close
|
|
86
|
+
line_volume = lines.volume
|
|
87
|
+
line_openinterest = lines.openinterest
|
|
88
|
+
self._btcsv_line_refs = (
|
|
89
|
+
line_datetime,
|
|
90
|
+
line_open,
|
|
91
|
+
line_high,
|
|
92
|
+
line_low,
|
|
93
|
+
line_close,
|
|
94
|
+
line_volume,
|
|
95
|
+
line_openinterest,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Date processing
|
|
99
|
+
dttxt = linetokens[0] # The Format is YYYY-MM-DD - skip char 4 and 7
|
|
100
|
+
year = int(dttxt[0:4])
|
|
101
|
+
month = int(dttxt[5:7])
|
|
102
|
+
day = int(dttxt[8:10])
|
|
103
|
+
dtnum = float(date(year, month, day).toordinal())
|
|
104
|
+
# If there are 8 columns, time exists, second column is time, process time, if not 8 columns, no time, time uses sessionend
|
|
105
|
+
if len(linetokens) == 8:
|
|
106
|
+
tmtxt = linetokens[1] # Format if present HH:MM:SS, skip 3 and 6
|
|
107
|
+
dtnum = math.fsum(
|
|
108
|
+
(
|
|
109
|
+
dtnum,
|
|
110
|
+
int(tmtxt[0:2]) / _HOURS_PER_DAY,
|
|
111
|
+
int(tmtxt[3:5]) / _MINUTES_PER_DAY,
|
|
112
|
+
int(tmtxt[6:8]) / _SECONDS_PER_DAY,
|
|
113
|
+
0.0,
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
offset = 2
|
|
117
|
+
else:
|
|
118
|
+
tm = self.p.sessionend # end of the session parameter
|
|
119
|
+
dtnum = math.fsum(
|
|
120
|
+
(
|
|
121
|
+
dtnum,
|
|
122
|
+
tm.hour / _HOURS_PER_DAY,
|
|
123
|
+
tm.minute / _MINUTES_PER_DAY,
|
|
124
|
+
tm.second / _SECONDS_PER_DAY,
|
|
125
|
+
tm.microsecond / _MICROSECONDS_PER_DAY,
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
offset = 1
|
|
129
|
+
open_value = float(linetokens[offset])
|
|
130
|
+
high_value = float(linetokens[offset + 1])
|
|
131
|
+
low_value = float(linetokens[offset + 2])
|
|
132
|
+
close_value = float(linetokens[offset + 3])
|
|
133
|
+
volume_value = float(linetokens[offset + 4])
|
|
134
|
+
openinterest_value = float(linetokens[offset + 5])
|
|
135
|
+
|
|
136
|
+
idx_datetime = line_datetime._idx
|
|
137
|
+
idx_open = line_open._idx
|
|
138
|
+
idx_high = line_high._idx
|
|
139
|
+
idx_low = line_low._idx
|
|
140
|
+
idx_close = line_close._idx
|
|
141
|
+
idx_volume = line_volume._idx
|
|
142
|
+
idx_openinterest = line_openinterest._idx
|
|
143
|
+
if (
|
|
144
|
+
idx_datetime >= 0
|
|
145
|
+
and idx_open >= 0
|
|
146
|
+
and idx_high >= 0
|
|
147
|
+
and idx_low >= 0
|
|
148
|
+
and idx_close >= 0
|
|
149
|
+
and idx_volume >= 0
|
|
150
|
+
and idx_openinterest >= 0
|
|
151
|
+
and not line_datetime.bindings
|
|
152
|
+
and not line_open.bindings
|
|
153
|
+
and not line_high.bindings
|
|
154
|
+
and not line_low.bindings
|
|
155
|
+
and not line_close.bindings
|
|
156
|
+
and not line_volume.bindings
|
|
157
|
+
and not line_openinterest.bindings
|
|
158
|
+
):
|
|
159
|
+
if open_value in (_INF, _NEG_INF):
|
|
160
|
+
open_value = line_open._default_value
|
|
161
|
+
if high_value in (_INF, _NEG_INF):
|
|
162
|
+
high_value = line_high._default_value
|
|
163
|
+
if low_value in (_INF, _NEG_INF):
|
|
164
|
+
low_value = line_low._default_value
|
|
165
|
+
if close_value in (_INF, _NEG_INF):
|
|
166
|
+
close_value = line_close._default_value
|
|
167
|
+
if volume_value in (_INF, _NEG_INF):
|
|
168
|
+
volume_value = line_volume._default_value
|
|
169
|
+
if openinterest_value in (_INF, _NEG_INF):
|
|
170
|
+
openinterest_value = line_openinterest._default_value
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
line_datetime.array[idx_datetime] = dtnum
|
|
174
|
+
line_open.array[idx_open] = open_value
|
|
175
|
+
line_high.array[idx_high] = high_value
|
|
176
|
+
line_low.array[idx_low] = low_value
|
|
177
|
+
line_close.array[idx_close] = close_value
|
|
178
|
+
line_volume.array[idx_volume] = volume_value
|
|
179
|
+
line_openinterest.array[idx_openinterest] = openinterest_value
|
|
180
|
+
return True
|
|
181
|
+
except IndexError:
|
|
182
|
+
logger.debug("btcsv:181 ignored IndexError")
|
|
183
|
+
|
|
184
|
+
# Fallback preserves binding propagation and LineBuffer boundary handling.
|
|
185
|
+
set_current = _set_current_value
|
|
186
|
+
set_current(line_datetime, dtnum)
|
|
187
|
+
set_current(line_open, open_value)
|
|
188
|
+
set_current(line_high, high_value)
|
|
189
|
+
set_current(line_low, low_value)
|
|
190
|
+
set_current(line_close, close_value)
|
|
191
|
+
set_current(line_volume, volume_value)
|
|
192
|
+
set_current(line_openinterest, openinterest_value)
|
|
193
|
+
|
|
194
|
+
return True
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class BacktraderCSV(feed.CSVFeedBase):
|
|
198
|
+
"""Backtrader CSV feed class.
|
|
199
|
+
|
|
200
|
+
Wrapper class for BacktraderCSVData feed functionality.
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
DataCls = BacktraderCSVData
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Chainer Data Feed Module - Chain multiple data feeds.
|
|
3
|
+
|
|
4
|
+
This module provides the Chainer feed for chaining multiple data
|
|
5
|
+
feeds together seamlessly during backtesting.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
Chainer: Chains multiple data feeds together.
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
>>> data1 = bt.feeds.BacktraderCSVData(dataname='part1.csv')
|
|
12
|
+
>>> data2 = bt.feeds.BacktraderCSVData(dataname='part2.csv')
|
|
13
|
+
>>> data = bt.feeds.Chainer(data1, data2)
|
|
14
|
+
>>> cerebro.adddata(data)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
|
|
19
|
+
from backtrader.utils.py3 import range
|
|
20
|
+
|
|
21
|
+
from ..feed import DataBase
|
|
22
|
+
from ..utils import date
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Chainer(DataBase):
|
|
26
|
+
"""Class that chains datas"""
|
|
27
|
+
|
|
28
|
+
# When data is live data, will avoid preloading and runonce behavior
|
|
29
|
+
def islive(self):
|
|
30
|
+
"""Returns ``True`` to notify ``Cerebro`` that preloading and runonce
|
|
31
|
+
should be deactivated"""
|
|
32
|
+
return True
|
|
33
|
+
|
|
34
|
+
def __init__(self, *args, **kwargs):
|
|
35
|
+
"""Initialize the Chainer data feed.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
*args: Data feeds to chain together.
|
|
39
|
+
**kwargs: Keyword arguments for data feed configuration.
|
|
40
|
+
"""
|
|
41
|
+
# Handle timeframe and compression parameters, originally handled by metaclass
|
|
42
|
+
if args:
|
|
43
|
+
# Copy timeframe and compression from first data source
|
|
44
|
+
kwargs.setdefault("timeframe", getattr(args[0], "_timeframe", None))
|
|
45
|
+
kwargs.setdefault("compression", getattr(args[0], "_compression", None))
|
|
46
|
+
|
|
47
|
+
super().__init__(**kwargs)
|
|
48
|
+
|
|
49
|
+
self._lastdt = None
|
|
50
|
+
self._d = None
|
|
51
|
+
self._ds = None
|
|
52
|
+
self._args = args
|
|
53
|
+
|
|
54
|
+
def start(self):
|
|
55
|
+
"""Start the Chainer data feed.
|
|
56
|
+
|
|
57
|
+
Initializes all chained data feeds.
|
|
58
|
+
"""
|
|
59
|
+
super().start()
|
|
60
|
+
for d in self._args:
|
|
61
|
+
d.setenvironment(self._env)
|
|
62
|
+
d._start()
|
|
63
|
+
|
|
64
|
+
# put the references in a separate list to have pops
|
|
65
|
+
self._ds = list(self._args)
|
|
66
|
+
self._d = self._ds.pop(0) if self._ds else None
|
|
67
|
+
self._lastdt = datetime.min
|
|
68
|
+
|
|
69
|
+
def stop(self):
|
|
70
|
+
"""Stop the Chainer data feed.
|
|
71
|
+
|
|
72
|
+
Stops all underlying data feeds.
|
|
73
|
+
"""
|
|
74
|
+
super().stop()
|
|
75
|
+
for d in self._args:
|
|
76
|
+
d.stop()
|
|
77
|
+
|
|
78
|
+
def get_notifications(self):
|
|
79
|
+
"""Get notifications from the current data feed.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
list: Notifications from active data feed or empty list.
|
|
83
|
+
"""
|
|
84
|
+
return [] if self._d is None else self._d.get_notifications()
|
|
85
|
+
|
|
86
|
+
# Get timezone
|
|
87
|
+
def _gettz(self):
|
|
88
|
+
"""To be overriden by subclasses which may auto-calculate the
|
|
89
|
+
timezone"""
|
|
90
|
+
if self._args:
|
|
91
|
+
return self._args[0]._gettz()
|
|
92
|
+
return date.Localizer(self.p.tz)
|
|
93
|
+
|
|
94
|
+
# Load data, this processing looks quite clever, planning to handle futures contract rollover or remove data when it expires later
|
|
95
|
+
def _load(self):
|
|
96
|
+
while self._d is not None:
|
|
97
|
+
if not self._d.next(): # no values from current data source
|
|
98
|
+
self._d = self._ds.pop(0) if self._ds else None
|
|
99
|
+
continue
|
|
100
|
+
|
|
101
|
+
# Cannot deliver a date equal or less than an already delivered
|
|
102
|
+
dt = self._d.datetime.datetime()
|
|
103
|
+
if dt <= self._lastdt:
|
|
104
|
+
continue
|
|
105
|
+
|
|
106
|
+
self._lastdt = dt
|
|
107
|
+
|
|
108
|
+
for i in range(self._d.size()):
|
|
109
|
+
self.lines[i][0] = self._d.lines[i][0]
|
|
110
|
+
|
|
111
|
+
return True
|
|
112
|
+
|
|
113
|
+
# Out of the loop -> self._d is None, no data feed to return from
|
|
114
|
+
return False
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Historical cryptocurrency data feed backed by CryptoHFTData."""
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
from typing import Any, Dict, Iterator
|
|
7
|
+
|
|
8
|
+
import pandas as pd
|
|
9
|
+
|
|
10
|
+
from ..dataseries import TimeFrame
|
|
11
|
+
from ..feed import DataBase
|
|
12
|
+
from ..utils import date2num
|
|
13
|
+
from ..utils.log_message import get_logger
|
|
14
|
+
|
|
15
|
+
logger = get_logger(__name__)
|
|
16
|
+
|
|
17
|
+
__all__ = ["CryptoHFTData"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
_TIMEFRAME_RULES = {
|
|
21
|
+
TimeFrame.Seconds: "s",
|
|
22
|
+
TimeFrame.Minutes: "min",
|
|
23
|
+
TimeFrame.Days: "D",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class CryptoHFTData(DataBase):
|
|
28
|
+
"""Load historical exchange trades from CryptoHFTData.
|
|
29
|
+
|
|
30
|
+
Tick requests emit one OHLCV-shaped backtrader bar per trade. Second,
|
|
31
|
+
minute, and daily requests aggregate the same trades into UTC-aligned
|
|
32
|
+
bars. Use ``TimeFrame.Minutes`` with ``compression=60`` for hourly bars.
|
|
33
|
+
|
|
34
|
+
``fromdate`` and ``todate`` are required to avoid accidental unbounded
|
|
35
|
+
high-frequency downloads. Naive datetimes are interpreted as UTC.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
params = (
|
|
39
|
+
("exchange", None),
|
|
40
|
+
("api_key", None),
|
|
41
|
+
("client", None),
|
|
42
|
+
("timeframe", TimeFrame.Minutes),
|
|
43
|
+
("compression", 1),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def __init__(self):
|
|
47
|
+
"""Initialize an empty historical row iterator."""
|
|
48
|
+
super().__init__()
|
|
49
|
+
self._rows: Iterator[Dict[str, Any]] = iter(())
|
|
50
|
+
|
|
51
|
+
def start(self):
|
|
52
|
+
"""Download the requested trades and prepare chronological bars."""
|
|
53
|
+
super().start()
|
|
54
|
+
if not self.p.dataname:
|
|
55
|
+
raise ValueError("CryptoHFTData requires dataname to be a symbol such as BTCUSDT")
|
|
56
|
+
if not self.p.exchange:
|
|
57
|
+
raise ValueError("CryptoHFTData requires an exchange such as binance_futures")
|
|
58
|
+
if self.p.fromdate is None or self.p.todate is None:
|
|
59
|
+
raise ValueError("CryptoHFTData requires both fromdate and todate")
|
|
60
|
+
if self.p.compression < 1:
|
|
61
|
+
raise ValueError("CryptoHFTData compression must be at least 1")
|
|
62
|
+
|
|
63
|
+
start = _as_utc(self.p.fromdate)
|
|
64
|
+
end = _as_utc(self.p.todate)
|
|
65
|
+
if end < start:
|
|
66
|
+
raise ValueError("CryptoHFTData todate must not precede fromdate")
|
|
67
|
+
|
|
68
|
+
client = self.p.client or self._create_client()
|
|
69
|
+
trades = client.get_trades(
|
|
70
|
+
symbol=str(self.p.dataname).upper(),
|
|
71
|
+
exchange=self.p.exchange,
|
|
72
|
+
start_date=start.date().isoformat(),
|
|
73
|
+
end_date=end.date().isoformat(),
|
|
74
|
+
)
|
|
75
|
+
self._rows = iter(self._prepare_rows(trades, start, end))
|
|
76
|
+
|
|
77
|
+
def _create_client(self):
|
|
78
|
+
"""Create the optional CryptoHFTData SDK client lazily."""
|
|
79
|
+
try:
|
|
80
|
+
from cryptohftdata import CryptoHFTDataClient
|
|
81
|
+
except ImportError as exc:
|
|
82
|
+
logger.error("cryptohftdata:81 re-raising ImportError", exc_info=True)
|
|
83
|
+
raise ImportError(
|
|
84
|
+
"CryptoHFTData feed requires the optional dependency; "
|
|
85
|
+
"install backtrader[cryptohftdata]"
|
|
86
|
+
) from exc
|
|
87
|
+
|
|
88
|
+
api_key = self.p.api_key or os.getenv("CRYPTOHFTDATA_API_KEY") or None
|
|
89
|
+
return CryptoHFTDataClient(api_key=api_key)
|
|
90
|
+
|
|
91
|
+
def _prepare_rows(self, trades, start: datetime, end: datetime):
|
|
92
|
+
"""Normalize SDK trades and optionally aggregate them into bars."""
|
|
93
|
+
required = {"trade_time", "trade_id", "price", "quantity"}
|
|
94
|
+
missing = required.difference(trades.columns)
|
|
95
|
+
if missing:
|
|
96
|
+
raise ValueError(
|
|
97
|
+
"CryptoHFTData response is missing required columns: " + ", ".join(sorted(missing))
|
|
98
|
+
)
|
|
99
|
+
if trades.empty:
|
|
100
|
+
return []
|
|
101
|
+
|
|
102
|
+
frame = trades.copy()
|
|
103
|
+
frame["datetime"] = pd.to_datetime(frame["trade_time"], unit="ms", utc=True)
|
|
104
|
+
frame["price"] = pd.to_numeric(frame["price"], errors="coerce")
|
|
105
|
+
frame["quantity"] = pd.to_numeric(frame["quantity"], errors="coerce")
|
|
106
|
+
frame = frame.dropna(subset=["datetime", "price", "quantity"])
|
|
107
|
+
frame = frame.loc[
|
|
108
|
+
(frame["datetime"] >= pd.Timestamp(start)) & (frame["datetime"] <= pd.Timestamp(end))
|
|
109
|
+
]
|
|
110
|
+
frame = frame.sort_values(["trade_time", "trade_id"], kind="stable")
|
|
111
|
+
|
|
112
|
+
if self.p.timeframe == TimeFrame.Ticks:
|
|
113
|
+
frame = frame.assign(
|
|
114
|
+
open=frame["price"],
|
|
115
|
+
high=frame["price"],
|
|
116
|
+
low=frame["price"],
|
|
117
|
+
close=frame["price"],
|
|
118
|
+
volume=frame["quantity"],
|
|
119
|
+
)
|
|
120
|
+
return frame[["datetime", "open", "high", "low", "close", "volume"]].to_dict("records")
|
|
121
|
+
|
|
122
|
+
suffix = _TIMEFRAME_RULES.get(self.p.timeframe)
|
|
123
|
+
if suffix is None:
|
|
124
|
+
name = TimeFrame.getname(self.p.timeframe, self.p.compression)
|
|
125
|
+
raise ValueError(f"CryptoHFTData does not support the {name} timeframe")
|
|
126
|
+
rule = f"{self.p.compression}{suffix}"
|
|
127
|
+
bars = (
|
|
128
|
+
frame.set_index("datetime")
|
|
129
|
+
.resample(rule, label="left", closed="left")
|
|
130
|
+
.agg(
|
|
131
|
+
open=("price", "first"),
|
|
132
|
+
high=("price", "max"),
|
|
133
|
+
low=("price", "min"),
|
|
134
|
+
close=("price", "last"),
|
|
135
|
+
volume=("quantity", "sum"),
|
|
136
|
+
)
|
|
137
|
+
.dropna(subset=["open"])
|
|
138
|
+
.reset_index()
|
|
139
|
+
)
|
|
140
|
+
return bars.to_dict("records")
|
|
141
|
+
|
|
142
|
+
def _load(self):
|
|
143
|
+
"""Emit the next normalized trade or bar."""
|
|
144
|
+
try:
|
|
145
|
+
row = next(self._rows)
|
|
146
|
+
except StopIteration:
|
|
147
|
+
return False
|
|
148
|
+
|
|
149
|
+
timestamp = row["datetime"].to_pydatetime().astimezone(timezone.utc).replace(tzinfo=None)
|
|
150
|
+
self.lines.datetime[0] = date2num(timestamp)
|
|
151
|
+
self.lines.open[0] = float(row["open"])
|
|
152
|
+
self.lines.high[0] = float(row["high"])
|
|
153
|
+
self.lines.low[0] = float(row["low"])
|
|
154
|
+
self.lines.close[0] = float(row["close"])
|
|
155
|
+
self.lines.volume[0] = float(row["volume"])
|
|
156
|
+
self.lines.openinterest[0] = 0.0
|
|
157
|
+
return True
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _as_utc(value: datetime) -> datetime:
|
|
161
|
+
"""Return an aware UTC datetime, interpreting naive values as UTC."""
|
|
162
|
+
if value.tzinfo is None:
|
|
163
|
+
return value.replace(tzinfo=timezone.utc)
|
|
164
|
+
return value.astimezone(timezone.utc)
|