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,245 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""VWR Analyzer Module - Variability-Weighted Return calculation.
|
|
3
|
+
|
|
4
|
+
This module provides the VWR (Variability-Weighted Return) analyzer,
|
|
5
|
+
an alternative to the Sharpe ratio using log returns.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
VWR: Analyzer that calculates VWR metric.
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
>>> cerebro = bt.Cerebro()
|
|
12
|
+
>>> cerebro.addanalyzer(bt.analyzers.VWR, _name='vwr')
|
|
13
|
+
>>> results = cerebro.run()
|
|
14
|
+
>>> print(results[0].analyzers.vwr.get_analysis())
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import math
|
|
18
|
+
|
|
19
|
+
from ..analyzer import TimeFrameAnalyzerBase
|
|
20
|
+
from ..dataseries import TimeFrame
|
|
21
|
+
from ..mathsupport import standarddev
|
|
22
|
+
from ..metabase import OwnerContext
|
|
23
|
+
from .returns import Returns
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Get VWR indicator
|
|
27
|
+
class VWR(TimeFrameAnalyzerBase):
|
|
28
|
+
"""Variability-Weighted Return: Better SharpeRatio with Log Returns
|
|
29
|
+
|
|
30
|
+
Alias:
|
|
31
|
+
|
|
32
|
+
- VariabilityWeightedReturn
|
|
33
|
+
|
|
34
|
+
See:
|
|
35
|
+
|
|
36
|
+
- https://www.crystalbull.com/sharpe-ratio-better-with-log-returns/
|
|
37
|
+
|
|
38
|
+
Params:
|
|
39
|
+
|
|
40
|
+
- ``timeframe`` (default: ``None``)
|
|
41
|
+
If ``None`` then the complete return over the entire backtested period
|
|
42
|
+
will be reported
|
|
43
|
+
|
|
44
|
+
Pass ``TimeFrame.NoTimeFrame`` to consider the entire dataset with no
|
|
45
|
+
time constraints
|
|
46
|
+
|
|
47
|
+
- ``compression`` (default: ``None``)
|
|
48
|
+
|
|
49
|
+
Only used for sub-day timeframes to, for example, work on an hourly
|
|
50
|
+
timeframe by specifying "TimeFrame.Minutes" and 60 as compression
|
|
51
|
+
|
|
52
|
+
If `None`, then the compression of the first data in the system will be
|
|
53
|
+
used
|
|
54
|
+
|
|
55
|
+
- ``tann`` (default: ``None``)
|
|
56
|
+
|
|
57
|
+
Number of periods to use for the annualization (normalization) of the
|
|
58
|
+
average returns. If ``None``, then standard ``t`` values will be used,
|
|
59
|
+
namely:
|
|
60
|
+
|
|
61
|
+
- ``days: 252``
|
|
62
|
+
- ``weeks: 52``
|
|
63
|
+
- ``months: 12``
|
|
64
|
+
- ``years: 1``
|
|
65
|
+
|
|
66
|
+
- ``tau`` (default: ``2.0``)
|
|
67
|
+
|
|
68
|
+
Factor for the calculation (see the literature)
|
|
69
|
+
|
|
70
|
+
- ``sdev_max`` (default: ``0.20``)
|
|
71
|
+
|
|
72
|
+
Max standard deviation (see the literature)
|
|
73
|
+
|
|
74
|
+
- ``fund`` (default: ``None``)
|
|
75
|
+
|
|
76
|
+
If `None`, the actual mode of the broker (fundmode - True/False) will
|
|
77
|
+
be autodetected to decide if the returns are based on the total net
|
|
78
|
+
asset value or on the fund value. See ``set_fundmode`` in the broker
|
|
79
|
+
documentation
|
|
80
|
+
|
|
81
|
+
Set it to ``True`` or ``False`` for a specific behavior
|
|
82
|
+
|
|
83
|
+
Methods:
|
|
84
|
+
|
|
85
|
+
- Get_analysis
|
|
86
|
+
|
|
87
|
+
Returns a dictionary with returns as values and the datetime points for
|
|
88
|
+
each return as keys
|
|
89
|
+
|
|
90
|
+
The returned dict contains the following keys:
|
|
91
|
+
|
|
92
|
+
- ``vwr``: Variability-Weighted Return
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
# Parameters
|
|
96
|
+
params = (
|
|
97
|
+
("tann", None),
|
|
98
|
+
("tau", 0.20),
|
|
99
|
+
("sdev_max", 2.0),
|
|
100
|
+
("fund", None),
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# Trading periods per year
|
|
104
|
+
_TANN = {
|
|
105
|
+
TimeFrame.Days: 252.0,
|
|
106
|
+
TimeFrame.Weeks: 52.0,
|
|
107
|
+
TimeFrame.Months: 12.0,
|
|
108
|
+
TimeFrame.Years: 1.0,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Initialize, get returns
|
|
112
|
+
def __init__(self, *args, **kwargs):
|
|
113
|
+
"""Initialize the VWR analyzer.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
*args: Positional arguments.
|
|
117
|
+
**kwargs: Keyword arguments for analyzer parameters.
|
|
118
|
+
"""
|
|
119
|
+
# Call parent class __init__ method to support timeframe and compression parameters
|
|
120
|
+
super().__init__(*args, **kwargs)
|
|
121
|
+
|
|
122
|
+
# Children log return analyzer
|
|
123
|
+
self._pns = None
|
|
124
|
+
self._pis = None
|
|
125
|
+
self._fundmode = None
|
|
126
|
+
# Use OwnerContext so child analyzer can find this as its parent
|
|
127
|
+
with OwnerContext.set_owner(self):
|
|
128
|
+
self._returns = Returns(
|
|
129
|
+
timeframe=self.p.timeframe, compression=self.p.compression, tann=self.p.tann
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Start
|
|
133
|
+
def start(self):
|
|
134
|
+
"""Initialize the analyzer at the start of the backtest.
|
|
135
|
+
|
|
136
|
+
Sets the fund mode and initializes lists to track period
|
|
137
|
+
start and end values.
|
|
138
|
+
"""
|
|
139
|
+
super().start()
|
|
140
|
+
# Add an initial placeholder for [-1] operation
|
|
141
|
+
# Get fundmode
|
|
142
|
+
if self.p.fund is None:
|
|
143
|
+
self._fundmode = self.strategy.broker.fundmode
|
|
144
|
+
else:
|
|
145
|
+
self._fundmode = self.p.fund
|
|
146
|
+
# Get initial value based on fundmode
|
|
147
|
+
if not self._fundmode:
|
|
148
|
+
self._pis = [self.strategy.broker.getvalue()] # keep initial value
|
|
149
|
+
else:
|
|
150
|
+
self._pis = [self.strategy.broker.fundvalue] # keep initial value
|
|
151
|
+
# Initialize final value to None
|
|
152
|
+
self._pns = [None] # keep final prices (value)
|
|
153
|
+
|
|
154
|
+
# Stop
|
|
155
|
+
def stop(self):
|
|
156
|
+
"""Calculate the VWR metric when backtest ends.
|
|
157
|
+
|
|
158
|
+
VWR = rnorm100 * (1 - (sdev_p / sdev_max)^tau)
|
|
159
|
+
where sdev_p is the standard deviation of period returns.
|
|
160
|
+
"""
|
|
161
|
+
super().stop()
|
|
162
|
+
# Check if no value has been seen after the last 'dt_over'
|
|
163
|
+
# If so, there is one 'pi' out of place and a None 'pn'. Purge
|
|
164
|
+
# If the last value is None, remove the last element
|
|
165
|
+
if self._pns[-1] is None:
|
|
166
|
+
self._pis.pop()
|
|
167
|
+
self._pns.pop()
|
|
168
|
+
|
|
169
|
+
# Get results from children
|
|
170
|
+
# Get returns
|
|
171
|
+
rs = self._returns.get_analysis()
|
|
172
|
+
ravg = rs["ravg"]
|
|
173
|
+
rnorm100 = rs["rnorm100"]
|
|
174
|
+
|
|
175
|
+
# make n 1 based in enumerate (number of periods and not index)
|
|
176
|
+
# skip initial placeholders for synchronization
|
|
177
|
+
# Calculate return for each period (usually yearly, then save to dts)
|
|
178
|
+
dts = []
|
|
179
|
+
invalid_input = False
|
|
180
|
+
for n, pipn in enumerate(zip(self._pis, self._pns), 1):
|
|
181
|
+
pi, pn = pipn
|
|
182
|
+
try:
|
|
183
|
+
dt = pn / (pi * math.exp(ravg * n)) - 1.0
|
|
184
|
+
if isinstance(dt, complex) or not math.isfinite(dt):
|
|
185
|
+
invalid_input = True
|
|
186
|
+
dt = 0.0
|
|
187
|
+
except (ZeroDivisionError, TypeError, ValueError, OverflowError):
|
|
188
|
+
invalid_input = True
|
|
189
|
+
dt = 0.0
|
|
190
|
+
if not math.isfinite(dt):
|
|
191
|
+
invalid_input = True
|
|
192
|
+
dt = 0.0
|
|
193
|
+
dts.append(dt)
|
|
194
|
+
# Calculate standard deviation of annual returns
|
|
195
|
+
sdev_p = standarddev(dts, bessel=True)
|
|
196
|
+
# Calculate VWR value
|
|
197
|
+
try:
|
|
198
|
+
invalid_output = (
|
|
199
|
+
invalid_input
|
|
200
|
+
or isinstance(sdev_p, complex)
|
|
201
|
+
or not math.isfinite(sdev_p)
|
|
202
|
+
or isinstance(rnorm100, complex)
|
|
203
|
+
or not math.isfinite(rnorm100)
|
|
204
|
+
)
|
|
205
|
+
except TypeError:
|
|
206
|
+
invalid_output = True
|
|
207
|
+
if invalid_output:
|
|
208
|
+
vwr = 0.0
|
|
209
|
+
elif self.p.sdev_max:
|
|
210
|
+
try:
|
|
211
|
+
vwr = rnorm100 * (1.0 - pow(sdev_p / self.p.sdev_max, self.p.tau))
|
|
212
|
+
if isinstance(vwr, complex) or not math.isfinite(vwr):
|
|
213
|
+
vwr = 0.0
|
|
214
|
+
except (ZeroDivisionError, TypeError, ValueError, OverflowError):
|
|
215
|
+
vwr = 0.0
|
|
216
|
+
else:
|
|
217
|
+
vwr = 0.0
|
|
218
|
+
self.rets["vwr"] = vwr
|
|
219
|
+
|
|
220
|
+
# Fund notification
|
|
221
|
+
def notify_fund(self, cash, value, fundvalue, shares):
|
|
222
|
+
"""Update the current period end value from fund notification.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
cash: Current cash amount.
|
|
226
|
+
value: Current portfolio value.
|
|
227
|
+
fundvalue: Current fund value.
|
|
228
|
+
shares: Number of fund shares.
|
|
229
|
+
"""
|
|
230
|
+
if not self._fundmode:
|
|
231
|
+
self._pns[-1] = value # annotate last seen pn for the current period
|
|
232
|
+
else:
|
|
233
|
+
self._pns[-1] = fundvalue # annotate last pn for current period
|
|
234
|
+
|
|
235
|
+
def on_dt_over(self):
|
|
236
|
+
"""Handle timeframe boundary crossing.
|
|
237
|
+
|
|
238
|
+
Moves the current period end value to be the next period's
|
|
239
|
+
start value and creates a new placeholder.
|
|
240
|
+
"""
|
|
241
|
+
self._pis.append(self._pns[-1]) # the last pn is pi in the next period
|
|
242
|
+
self._pns.append(None) # placeholder for [-1] operation
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
VariabilityWeightedReturn = VWR
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Backtrader Bokeh Module
|
|
4
|
+
|
|
5
|
+
Provides Bokeh-based live plotting functionality, including:
|
|
6
|
+
- Real-time data push and chart updates
|
|
7
|
+
- Extensible tab system
|
|
8
|
+
- Navigation controls (pause/play/forward/backward)
|
|
9
|
+
- Theme system (black/white themes)
|
|
10
|
+
- Memory optimization (lookback control)
|
|
11
|
+
|
|
12
|
+
Example:
|
|
13
|
+
import backtrader as bt
|
|
14
|
+
from backtrader.bokeh import LivePlotAnalyzer, Blackly
|
|
15
|
+
|
|
16
|
+
cerebro = bt.Cerebro()
|
|
17
|
+
cerebro.adddata(data)
|
|
18
|
+
cerebro.addstrategy(MyStrategy)
|
|
19
|
+
|
|
20
|
+
# Add live plot analyzer
|
|
21
|
+
cerebro.addanalyzer(LivePlotAnalyzer,
|
|
22
|
+
scheme=Blackly(),
|
|
23
|
+
lookback=100)
|
|
24
|
+
|
|
25
|
+
cerebro.run()
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
import importlib
|
|
29
|
+
import os
|
|
30
|
+
import sys
|
|
31
|
+
|
|
32
|
+
_BOKEH_PACKAGE_ROOT = os.path.realpath(os.path.dirname(__file__))
|
|
33
|
+
_BOKEH_PACKAGE_PARENT = os.path.dirname(_BOKEH_PACKAGE_ROOT)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _is_local_bokeh_module(module):
|
|
37
|
+
"""Return whether a top-level ``bokeh`` module resolves to this package."""
|
|
38
|
+
module_file = getattr(module, "__file__", None)
|
|
39
|
+
if module_file and os.path.realpath(module_file).startswith(_BOKEH_PACKAGE_ROOT + os.sep):
|
|
40
|
+
return True
|
|
41
|
+
|
|
42
|
+
return any(
|
|
43
|
+
os.path.realpath(module_path) == _BOKEH_PACKAGE_ROOT
|
|
44
|
+
for module_path in getattr(module, "__path__", ())
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _ensure_external_bokeh():
|
|
49
|
+
"""Load the third-party Bokeh package when this package directory shadows it.
|
|
50
|
+
|
|
51
|
+
Some test and embedded environments add ``backtrader/`` directly to
|
|
52
|
+
``sys.path``. In that layout, a bare ``import bokeh`` resolves to this
|
|
53
|
+
package rather than the third-party dependency. Resolve the optional
|
|
54
|
+
dependency while temporarily excluding that shadowing path.
|
|
55
|
+
"""
|
|
56
|
+
loaded = sys.modules.get("bokeh")
|
|
57
|
+
if loaded is not None and not _is_local_bokeh_module(loaded):
|
|
58
|
+
return loaded
|
|
59
|
+
|
|
60
|
+
original_path = sys.path[:]
|
|
61
|
+
try:
|
|
62
|
+
sys.path[:] = [
|
|
63
|
+
entry
|
|
64
|
+
for entry in sys.path
|
|
65
|
+
if os.path.realpath(entry or os.getcwd()) != _BOKEH_PACKAGE_PARENT
|
|
66
|
+
]
|
|
67
|
+
for name in list(sys.modules):
|
|
68
|
+
module = sys.modules.get(name)
|
|
69
|
+
if name == "bokeh" or name.startswith("bokeh."):
|
|
70
|
+
if module is not None and _is_local_bokeh_module(module):
|
|
71
|
+
sys.modules.pop(name, None)
|
|
72
|
+
return importlib.import_module("bokeh")
|
|
73
|
+
except ImportError:
|
|
74
|
+
return None
|
|
75
|
+
finally:
|
|
76
|
+
sys.path[:] = original_path
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
_ensure_external_bokeh()
|
|
80
|
+
|
|
81
|
+
if __name__ != "bokeh":
|
|
82
|
+
from . import tabs
|
|
83
|
+
from .schemes import Blackly, Scheme, Tradimo
|
|
84
|
+
from .tab import BokehTab
|
|
85
|
+
from .utils import get_datanames, get_strategy_label, sanitize_source_name
|
|
86
|
+
|
|
87
|
+
# Custom tab registry
|
|
88
|
+
_custom_tabs = []
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def register_tab(tab_class):
|
|
92
|
+
"""Register a custom tab.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
tab_class: Tab class that inherits from BokehTab
|
|
96
|
+
"""
|
|
97
|
+
if not issubclass(tab_class, BokehTab):
|
|
98
|
+
raise ValueError("tab_class must be a subclass of BokehTab")
|
|
99
|
+
_custom_tabs.append(tab_class)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def get_registered_tabs():
|
|
103
|
+
"""Get all registered custom tabs."""
|
|
104
|
+
return _custom_tabs.copy()
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# Lazy import to avoid circular dependencies
|
|
108
|
+
def __getattr__(name):
|
|
109
|
+
"""Lazy load module attributes."""
|
|
110
|
+
if name == "BacktraderBokeh":
|
|
111
|
+
from .app import BacktraderBokeh
|
|
112
|
+
|
|
113
|
+
return BacktraderBokeh
|
|
114
|
+
if name == "LivePlotAnalyzer":
|
|
115
|
+
from .analyzers import LivePlotAnalyzer
|
|
116
|
+
|
|
117
|
+
return LivePlotAnalyzer
|
|
118
|
+
if name == "RecorderAnalyzer":
|
|
119
|
+
from .analyzers import RecorderAnalyzer
|
|
120
|
+
|
|
121
|
+
return RecorderAnalyzer
|
|
122
|
+
if name == "LiveClient":
|
|
123
|
+
from .live import LiveClient
|
|
124
|
+
|
|
125
|
+
return LiveClient
|
|
126
|
+
if name == "LiveDataHandler":
|
|
127
|
+
from .live import LiveDataHandler
|
|
128
|
+
|
|
129
|
+
return LiveDataHandler
|
|
130
|
+
if name == "BokehPlot":
|
|
131
|
+
from .plot_adapter import BokehPlot
|
|
132
|
+
|
|
133
|
+
return BokehPlot
|
|
134
|
+
|
|
135
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
__all__ = [
|
|
139
|
+
"BacktraderBokeh",
|
|
140
|
+
"Scheme",
|
|
141
|
+
"Blackly",
|
|
142
|
+
"Tradimo",
|
|
143
|
+
"BokehTab",
|
|
144
|
+
"LivePlotAnalyzer",
|
|
145
|
+
"RecorderAnalyzer",
|
|
146
|
+
"LiveClient",
|
|
147
|
+
"LiveDataHandler",
|
|
148
|
+
"BokehPlot",
|
|
149
|
+
"tabs",
|
|
150
|
+
"register_tab",
|
|
151
|
+
"get_registered_tabs",
|
|
152
|
+
"get_datanames",
|
|
153
|
+
"get_strategy_label",
|
|
154
|
+
"sanitize_source_name",
|
|
155
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Bokeh analyzers module.
|
|
4
|
+
|
|
5
|
+
Provides the following analyzers:
|
|
6
|
+
- LivePlotAnalyzer: Live plotting analyzer
|
|
7
|
+
- RecorderAnalyzer: Data recording analyzer
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from .plot import LivePlotAnalyzer
|
|
11
|
+
from .recorder import RecorderAnalyzer
|
|
12
|
+
|
|
13
|
+
__all__ = ["LivePlotAnalyzer", "RecorderAnalyzer"]
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Live plotting analyzer.
|
|
4
|
+
|
|
5
|
+
Provides real-time plotting functionality based on Bokeh Server.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import threading
|
|
10
|
+
from threading import Lock
|
|
11
|
+
|
|
12
|
+
from backtrader.utils.log_message import get_logger
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
import tornado.ioloop
|
|
16
|
+
|
|
17
|
+
TORNADO_AVAILABLE = True
|
|
18
|
+
except ImportError:
|
|
19
|
+
TORNADO_AVAILABLE = False
|
|
20
|
+
|
|
21
|
+
import backtrader as bt
|
|
22
|
+
|
|
23
|
+
from ..app import BacktraderBokeh
|
|
24
|
+
from ..live.client import LiveClient
|
|
25
|
+
from ..schemes import Tradimo
|
|
26
|
+
from ..webapp import Webapp
|
|
27
|
+
|
|
28
|
+
_logger = get_logger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class LivePlotAnalyzer(bt.Analyzer):
|
|
32
|
+
"""Live plotting analyzer.
|
|
33
|
+
|
|
34
|
+
Provides real-time plotting functionality based on Bokeh Server, including:
|
|
35
|
+
- WebSocket real-time data push
|
|
36
|
+
- Pause/resume functionality
|
|
37
|
+
- Forward/backward navigation
|
|
38
|
+
- Data lookback control
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
scheme: Theme instance, defaults to Tradimo
|
|
42
|
+
style: Chart style, 'bar' or 'candle'
|
|
43
|
+
lookback: Amount of historical data to retain
|
|
44
|
+
address: Server address
|
|
45
|
+
port: Server port
|
|
46
|
+
title: Title
|
|
47
|
+
autostart: Whether to auto-start the server
|
|
48
|
+
|
|
49
|
+
Example:
|
|
50
|
+
cerebro.addanalyzer(LivePlotAnalyzer,
|
|
51
|
+
scheme=Blackly(),
|
|
52
|
+
lookback=100,
|
|
53
|
+
port=8999)
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
params = (
|
|
57
|
+
("scheme", None), # Theme
|
|
58
|
+
("style", "bar"), # Chart style
|
|
59
|
+
("lookback", 100), # Historical data retention
|
|
60
|
+
("address", "localhost"), # Server address
|
|
61
|
+
("port", 8999), # Server port
|
|
62
|
+
("title", None), # Title
|
|
63
|
+
("autostart", True), # Auto-start
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
def __init__(self, **kwargs):
|
|
67
|
+
"""Initialize live plot analyzer.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
**kwargs: Keyword arguments overriding default parameters:
|
|
71
|
+
- scheme: Theme instance (defaults to Tradimo)
|
|
72
|
+
- style: Chart style ('bar' or 'candle')
|
|
73
|
+
- lookback: Number of bars to retain in display
|
|
74
|
+
- address: Server address (default: 'localhost')
|
|
75
|
+
- port: Server port (default: 8999)
|
|
76
|
+
- title: Chart title (default: 'Live {StrategyName}')
|
|
77
|
+
- autostart: Whether to auto-start server (default: True)
|
|
78
|
+
"""
|
|
79
|
+
super().__init__()
|
|
80
|
+
|
|
81
|
+
# Set title
|
|
82
|
+
title = self.p.title
|
|
83
|
+
if title is None:
|
|
84
|
+
title = f"Live {type(self.strategy).__name__}"
|
|
85
|
+
|
|
86
|
+
# Set auto-start
|
|
87
|
+
autostart = kwargs.get("autostart", self.p.autostart)
|
|
88
|
+
|
|
89
|
+
# Get theme
|
|
90
|
+
scheme = self.p.scheme
|
|
91
|
+
if scheme is None:
|
|
92
|
+
scheme = Tradimo()
|
|
93
|
+
|
|
94
|
+
# Create Webapp
|
|
95
|
+
self._webapp = Webapp(
|
|
96
|
+
title=title,
|
|
97
|
+
template="basic.html.j2",
|
|
98
|
+
scheme=scheme,
|
|
99
|
+
on_root_model=self._app_cb_build_root_model,
|
|
100
|
+
on_session_destroyed=self._on_session_destroyed,
|
|
101
|
+
autostart=autostart,
|
|
102
|
+
address=self.p.address,
|
|
103
|
+
port=self.p.port,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
self._lock = Lock()
|
|
107
|
+
self._clients = {}
|
|
108
|
+
self._app_kwargs = kwargs
|
|
109
|
+
|
|
110
|
+
def _create_app(self):
|
|
111
|
+
"""Create BacktraderBokeh application instance.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
BacktraderBokeh instance
|
|
115
|
+
"""
|
|
116
|
+
return BacktraderBokeh(
|
|
117
|
+
style=self.p.style, scheme=self.p.scheme or Tradimo(), **self._app_kwargs
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def _on_session_destroyed(self, session_context):
|
|
121
|
+
"""Session destroyed callback.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
session_context: Bokeh session context
|
|
125
|
+
"""
|
|
126
|
+
with self._lock:
|
|
127
|
+
session_id = session_context.id
|
|
128
|
+
if session_id in self._clients:
|
|
129
|
+
self._clients[session_id].stop()
|
|
130
|
+
del self._clients[session_id]
|
|
131
|
+
|
|
132
|
+
def _t_server(self):
|
|
133
|
+
"""Server thread method."""
|
|
134
|
+
if not TORNADO_AVAILABLE:
|
|
135
|
+
_logger.error("Tornado is not available. Cannot start Bokeh server.")
|
|
136
|
+
return
|
|
137
|
+
|
|
138
|
+
asyncio.set_event_loop(asyncio.new_event_loop())
|
|
139
|
+
loop = tornado.ioloop.IOLoop.current()
|
|
140
|
+
self._webapp.start(loop)
|
|
141
|
+
|
|
142
|
+
def _app_cb_build_root_model(self, doc):
|
|
143
|
+
"""Build root model callback.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
doc: Bokeh document
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
Root model
|
|
150
|
+
"""
|
|
151
|
+
client = LiveClient(doc, self._create_app(), self.strategy, self.p.lookback)
|
|
152
|
+
|
|
153
|
+
with self._lock:
|
|
154
|
+
self._clients[doc.session_context.id] = client
|
|
155
|
+
|
|
156
|
+
return client.model
|
|
157
|
+
|
|
158
|
+
def start(self):
|
|
159
|
+
"""Start from backtrader.
|
|
160
|
+
|
|
161
|
+
Starts the Bokeh Server.
|
|
162
|
+
"""
|
|
163
|
+
_logger.debug("Starting LivePlotAnalyzer...")
|
|
164
|
+
|
|
165
|
+
t = threading.Thread(target=self._t_server)
|
|
166
|
+
t.daemon = True
|
|
167
|
+
t.start()
|
|
168
|
+
|
|
169
|
+
def stop(self):
|
|
170
|
+
"""Stop from backtrader."""
|
|
171
|
+
_logger.debug("Stopping LivePlotAnalyzer...")
|
|
172
|
+
|
|
173
|
+
with self._lock:
|
|
174
|
+
for client in self._clients.values():
|
|
175
|
+
client.stop()
|
|
176
|
+
|
|
177
|
+
def next(self):
|
|
178
|
+
"""Receive new data from backtrader.
|
|
179
|
+
|
|
180
|
+
Updates all connected clients.
|
|
181
|
+
"""
|
|
182
|
+
with self._lock:
|
|
183
|
+
for client in self._clients.values():
|
|
184
|
+
client.next()
|
|
185
|
+
|
|
186
|
+
def get_analysis(self):
|
|
187
|
+
"""Return analysis results.
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
dict: Empty dict (this analyzer is for plotting, does not produce analysis data)
|
|
191
|
+
"""
|
|
192
|
+
return {}
|