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,179 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Custom Indicators Module - User-defined indicators.
|
|
3
|
+
|
|
4
|
+
This module contains custom indicator algorithms including:
|
|
5
|
+
- MaBetweenHighAndLow: Check if MA is within price range
|
|
6
|
+
- BarsLast: Count bars since condition was met
|
|
7
|
+
- NewDiff: Guotai Junan alpha factor indicator
|
|
8
|
+
|
|
9
|
+
Example:
|
|
10
|
+
To use these custom indicators in your strategy::
|
|
11
|
+
|
|
12
|
+
import backtrader as bt
|
|
13
|
+
|
|
14
|
+
class MyStrategy(bt.Strategy):
|
|
15
|
+
def __init__(self):
|
|
16
|
+
# Create MA Between High and Low indicator
|
|
17
|
+
self.ma_hl = bt.indicators.MaBetweenHighAndLow(
|
|
18
|
+
self.data, period=5
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# Create Bars Last indicator
|
|
22
|
+
self.bars_last = bt.indicators.BarsLast(
|
|
23
|
+
self.data, period=5
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Create NewDiff indicator (Guotai Junan alpha factor)
|
|
27
|
+
self.new_diff = bt.indicators.NewDiff(
|
|
28
|
+
self.data, period=6
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def next(self):
|
|
32
|
+
# Use the indicators in your trading logic
|
|
33
|
+
if self.ma_hl.target[0] > 0:
|
|
34
|
+
# MA is within high-low range
|
|
35
|
+
self.buy()
|
|
36
|
+
|
|
37
|
+
if self.bars_last.bar_num[0] < 3:
|
|
38
|
+
# Condition was met less than 3 bars ago
|
|
39
|
+
self.sell()
|
|
40
|
+
|
|
41
|
+
# Access the alpha factor value
|
|
42
|
+
alpha_value = self.new_diff.factor[0]
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
import math
|
|
46
|
+
|
|
47
|
+
import numpy as np
|
|
48
|
+
|
|
49
|
+
from . import SMA, If, Indicator, Max, Min
|
|
50
|
+
|
|
51
|
+
# This file contains some custom indicator algorithms
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class MaBetweenHighAndLow(Indicator):
|
|
55
|
+
"""Check if moving average is between high and low prices.
|
|
56
|
+
|
|
57
|
+
Returns 1.0 when SMA is within the bar's high-low range,
|
|
58
|
+
0.0 otherwise.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
# Check if moving average is between high and low prices
|
|
62
|
+
lines = ("target",)
|
|
63
|
+
params = (("period", 5),)
|
|
64
|
+
|
|
65
|
+
def __init__(self):
|
|
66
|
+
"""Initialize the MA Between High and Low indicator.
|
|
67
|
+
|
|
68
|
+
Creates SMA for comparison with high/low range.
|
|
69
|
+
"""
|
|
70
|
+
super().__init__()
|
|
71
|
+
self.ma = SMA(self.data.close, period=self.p.period)
|
|
72
|
+
|
|
73
|
+
def next(self):
|
|
74
|
+
"""Check if MA is between high and low for current bar.
|
|
75
|
+
|
|
76
|
+
Returns 1.0 if MA is within range, 0.0 otherwise.
|
|
77
|
+
"""
|
|
78
|
+
ma_val = self.ma[0]
|
|
79
|
+
high_val = self.data.high[0]
|
|
80
|
+
low_val = self.data.low[0]
|
|
81
|
+
self.lines.target[0] = 1.0 if (ma_val < high_val and ma_val > low_val) else 0.0
|
|
82
|
+
|
|
83
|
+
def once(self, start, end):
|
|
84
|
+
"""Check MA against high/low range in runonce mode.
|
|
85
|
+
|
|
86
|
+
Returns 1.0 where MA is within range, 0.0 otherwise.
|
|
87
|
+
"""
|
|
88
|
+
ma_array = self.ma.lines[0].array
|
|
89
|
+
high_array = self.data.high.array
|
|
90
|
+
low_array = self.data.low.array
|
|
91
|
+
larray = self.lines.target.array
|
|
92
|
+
|
|
93
|
+
while len(larray) < end:
|
|
94
|
+
larray.append(float("nan"))
|
|
95
|
+
|
|
96
|
+
for i in range(start, min(end, len(ma_array), len(high_array), len(low_array))):
|
|
97
|
+
ma_val = ma_array[i] if i < len(ma_array) else 0.0
|
|
98
|
+
high_val = high_array[i] if i < len(high_array) else 0.0
|
|
99
|
+
low_val = low_array[i] if i < len(low_array) else 0.0
|
|
100
|
+
|
|
101
|
+
if isinstance(ma_val, float) and math.isnan(ma_val):
|
|
102
|
+
larray[i] = float("nan")
|
|
103
|
+
else:
|
|
104
|
+
larray[i] = 1.0 if (ma_val < high_val and ma_val > low_val) else 0.0
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class BarsLast(Indicator):
|
|
108
|
+
"""Count bars since condition was last met.
|
|
109
|
+
|
|
110
|
+
Tracks the number of bars that have passed since a specified
|
|
111
|
+
condition (default: MaBetweenHighAndLow) was last true.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
# This indicator analyzes the number of bars since the last condition was met
|
|
115
|
+
lines = ("bar_num",)
|
|
116
|
+
params = (("period", 5), ("func", MaBetweenHighAndLow))
|
|
117
|
+
|
|
118
|
+
def __init__(self):
|
|
119
|
+
"""Initialize the Bars Last indicator.
|
|
120
|
+
|
|
121
|
+
Creates target function for condition checking.
|
|
122
|
+
"""
|
|
123
|
+
self.target = self.p.func(self.data, period=self.p.period)
|
|
124
|
+
self.num = np.nan
|
|
125
|
+
|
|
126
|
+
def next(self):
|
|
127
|
+
"""Count bars since condition was last met.
|
|
128
|
+
|
|
129
|
+
Resets to 0 when condition is true, increments otherwise.
|
|
130
|
+
"""
|
|
131
|
+
if self.target[0]:
|
|
132
|
+
self.num = 0
|
|
133
|
+
self.lines.bar_num[0] = self.num
|
|
134
|
+
self.num = self.num + 1
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class NewDiff(Indicator):
|
|
138
|
+
"""Guotai Junan alpha factor indicator.
|
|
139
|
+
|
|
140
|
+
Calculates a proprietary alpha factor based on price movement
|
|
141
|
+
relative to previous close and the high/low range.
|
|
142
|
+
|
|
143
|
+
Formula:
|
|
144
|
+
SUM((CLOSE==DELAY(CLOSE,1)?0:CLOSE-(CLOSE>DELAY(CLOSE,1)?
|
|
145
|
+
MIN(LOW,DELAY(CLOSE,1)):MAX(HIGH,DELAY(CLOSE,1)))), period)
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
# Indicator based on Guotai Junan alpha factor
|
|
149
|
+
# : SUM((CLOSE=DELAY(CLOSE,1)?0:CLOSE-(CLOSE>DELAY(CLOSE,1)?MIN(LOW,DELAY(CLOSE,1)):MAX(HIGH,DELAY(CLOSE,1)))),6)
|
|
150
|
+
# - e = MIN(LOW, DELAY(CLOSE, 1))
|
|
151
|
+
# - f = MAX(HIGH, DELAY(CLOSE, 1))
|
|
152
|
+
# - h = CLOSE > DELAY(CLOSE, 1)
|
|
153
|
+
# - b = h?e: f
|
|
154
|
+
# - a = CLOSE = DELAY(CLOSE, 1)?0: CLOSE - b
|
|
155
|
+
# - c = SUM(a, 6)
|
|
156
|
+
lines = ("factor",)
|
|
157
|
+
params = (("period", 5),)
|
|
158
|
+
|
|
159
|
+
def __init__(self):
|
|
160
|
+
"""Initialize the NewDiff indicator.
|
|
161
|
+
|
|
162
|
+
Sets up alpha factor calculation based on Guotai Junan formula.
|
|
163
|
+
"""
|
|
164
|
+
close = self.data.close
|
|
165
|
+
pre_close = self.data.close(-1)
|
|
166
|
+
e = Min(self.data.low, pre_close)
|
|
167
|
+
f = Max(self.data.high, pre_close)
|
|
168
|
+
b = If(close > pre_close, e, f)
|
|
169
|
+
self.a = If(close == pre_close, 0, close - b)
|
|
170
|
+
|
|
171
|
+
def next(self):
|
|
172
|
+
"""Calculate NewDiff factor for the current bar.
|
|
173
|
+
|
|
174
|
+
Sums adjusted price differences over the period.
|
|
175
|
+
"""
|
|
176
|
+
if len(self.a) >= self.p.period:
|
|
177
|
+
self.lines.factor[0] = math.fsum(self.a.get(size=self.p.period))
|
|
178
|
+
else:
|
|
179
|
+
self.lines.factor[0] = np.nan
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""On-Balance Volume indicator.
|
|
3
|
+
|
|
4
|
+
This module provides the On-Balance Volume (OBV) cumulative volume indicator.
|
|
5
|
+
OBV adds the current volume when the closing price rises, subtracts it when
|
|
6
|
+
it falls, and leaves the cumulative value unchanged when the closing price is
|
|
7
|
+
unchanged.
|
|
8
|
+
|
|
9
|
+
Classes:
|
|
10
|
+
OnBalanceVolume: On-Balance Volume indicator (alias: OBV).
|
|
11
|
+
|
|
12
|
+
Example:
|
|
13
|
+
class MyStrategy(bt.Strategy):
|
|
14
|
+
def __init__(self):
|
|
15
|
+
self.obv = bt.indicators.OBV(self.data)
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from . import Indicator
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class OnBalanceVolume(Indicator):
|
|
22
|
+
"""Cumulative On-Balance Volume indicator.
|
|
23
|
+
|
|
24
|
+
Formula:
|
|
25
|
+
- first value = volume
|
|
26
|
+
- close > previous close: obv = previous obv + volume
|
|
27
|
+
- close < previous close: obv = previous obv - volume
|
|
28
|
+
- close == previous close: obv = previous obv
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
alias = ("OBV",)
|
|
32
|
+
lines = ("obv",)
|
|
33
|
+
|
|
34
|
+
def __init__(self):
|
|
35
|
+
"""Initialize the indicator."""
|
|
36
|
+
super().__init__()
|
|
37
|
+
|
|
38
|
+
def nextstart(self):
|
|
39
|
+
"""Seed OBV with the first available volume value."""
|
|
40
|
+
self.lines.obv[0] = self.data.volume[0]
|
|
41
|
+
|
|
42
|
+
def next(self):
|
|
43
|
+
"""Update OBV for the current bar in event-driven mode."""
|
|
44
|
+
previous = self.lines.obv[-1]
|
|
45
|
+
close = self.data.close[0]
|
|
46
|
+
previous_close = self.data.close[-1]
|
|
47
|
+
volume = self.data.volume[0]
|
|
48
|
+
|
|
49
|
+
if close > previous_close:
|
|
50
|
+
self.lines.obv[0] = previous + volume
|
|
51
|
+
elif close < previous_close:
|
|
52
|
+
self.lines.obv[0] = previous - volume
|
|
53
|
+
else:
|
|
54
|
+
self.lines.obv[0] = previous
|
|
55
|
+
|
|
56
|
+
def oncestart(self, start, end):
|
|
57
|
+
"""Seed OBV in batch-processing mode."""
|
|
58
|
+
dst = self.lines.obv.array
|
|
59
|
+
volume = self.data.volume.array
|
|
60
|
+
|
|
61
|
+
while len(dst) < end:
|
|
62
|
+
dst.append(float("nan"))
|
|
63
|
+
|
|
64
|
+
for i in range(start, min(end, len(volume))):
|
|
65
|
+
dst[i] = volume[i]
|
|
66
|
+
|
|
67
|
+
def once(self, start, end):
|
|
68
|
+
"""Calculate OBV values in batch-processing mode."""
|
|
69
|
+
dst = self.lines.obv.array
|
|
70
|
+
close = self.data.close.array
|
|
71
|
+
volume = self.data.volume.array
|
|
72
|
+
actual_end = min(end, len(close), len(volume))
|
|
73
|
+
|
|
74
|
+
while len(dst) < end:
|
|
75
|
+
dst.append(float("nan"))
|
|
76
|
+
|
|
77
|
+
if start >= actual_end:
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
if start == 0:
|
|
81
|
+
dst[0] = volume[0]
|
|
82
|
+
start = 1
|
|
83
|
+
|
|
84
|
+
previous = dst[start - 1]
|
|
85
|
+
for i in range(start, actual_end):
|
|
86
|
+
if close[i] > close[i - 1]:
|
|
87
|
+
previous += volume[i]
|
|
88
|
+
elif close[i] < close[i - 1]:
|
|
89
|
+
previous -= volume[i]
|
|
90
|
+
|
|
91
|
+
dst[i] = previous
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
OBV = OnBalanceVolume
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""OLS Indicator Module - Ordinary least squares regression.
|
|
3
|
+
|
|
4
|
+
This module provides indicators using OLS (Ordinary Least Squares)
|
|
5
|
+
regression for statistical analysis.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
OLS_Slope_InterceptN: Calculates slope and intercept via OLS.
|
|
9
|
+
OLS_TransformationN: Calculates OLS transformed values.
|
|
10
|
+
OLS_BetaN: Calculates beta via OLS.
|
|
11
|
+
CointN: Tests for cointegration between series.
|
|
12
|
+
|
|
13
|
+
Example:
|
|
14
|
+
class MyStrategy(bt.Strategy):
|
|
15
|
+
def __init__(self):
|
|
16
|
+
# Calculate OLS regression slope and intercept between two data feeds
|
|
17
|
+
self.ols = bt.indicators.OLS_Slope_InterceptN(self.data0, self.data1, period=30)
|
|
18
|
+
|
|
19
|
+
# Calculate OLS transformation (spread, zscore)
|
|
20
|
+
self.ols_trans = bt.indicators.OLS_TransformationN(self.data0, self.data1, period=30)
|
|
21
|
+
|
|
22
|
+
def next(self):
|
|
23
|
+
# Trade based on zscore of the spread
|
|
24
|
+
if self.ols_trans.zscore[0] > 2:
|
|
25
|
+
# Spread is too high - short data0, long data1
|
|
26
|
+
self.sell(data=self.data0)
|
|
27
|
+
self.buy(data=self.data1)
|
|
28
|
+
elif self.ols_trans.zscore[0] < -2:
|
|
29
|
+
# Spread is too low - long data0, short data1
|
|
30
|
+
self.buy(data=self.data0)
|
|
31
|
+
self.sell(data=self.data1)
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
import pandas as pd
|
|
35
|
+
|
|
36
|
+
from . import PeriodN
|
|
37
|
+
|
|
38
|
+
# Lazy import statsmodels to avoid slow import at module load time
|
|
39
|
+
# statsmodels is a heavy library that adds 20+ seconds to import time
|
|
40
|
+
# It will be imported when the indicators are actually used
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _get_statsmodels():
|
|
44
|
+
"""Lazy import statsmodels.api."""
|
|
45
|
+
import statsmodels.api as sm
|
|
46
|
+
|
|
47
|
+
return sm
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _get_coint():
|
|
51
|
+
"""Lazy import statsmodels coint function."""
|
|
52
|
+
from statsmodels.tsa.stattools import coint
|
|
53
|
+
|
|
54
|
+
return coint
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
__all__ = ["OLS_Slope_InterceptN", "OLS_TransformationN", "OLS_BetaN", "CointN"]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class OLS_Slope_InterceptN(PeriodN):
|
|
61
|
+
"""
|
|
62
|
+
Calculates a linear regression using ``statsmodel.OLS`` (Ordinary least
|
|
63
|
+
squares) of data1 on data0
|
|
64
|
+
|
|
65
|
+
Uses ``pandas`` and ``statsmodels``
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
_mindatas = 2 # ensure at least 2 data feeds are passed
|
|
69
|
+
|
|
70
|
+
packages = (
|
|
71
|
+
("pandas", "pd"),
|
|
72
|
+
("statsmodels.api", "sm"),
|
|
73
|
+
)
|
|
74
|
+
lines = (
|
|
75
|
+
"slope",
|
|
76
|
+
"intercept",
|
|
77
|
+
)
|
|
78
|
+
params = (("period", 10),)
|
|
79
|
+
|
|
80
|
+
def next(self):
|
|
81
|
+
"""Calculate OLS slope and intercept for the current bar.
|
|
82
|
+
|
|
83
|
+
Uses statsmodels OLS to perform linear regression.
|
|
84
|
+
"""
|
|
85
|
+
sm = _get_statsmodels()
|
|
86
|
+
p0 = pd.Series(self.data0.get(size=self.p.period))
|
|
87
|
+
p1 = pd.Series(self.data1.get(size=self.p.period))
|
|
88
|
+
p1 = sm.add_constant(p1)
|
|
89
|
+
intercept, slope = sm.OLS(p0, p1).fit().params
|
|
90
|
+
|
|
91
|
+
self.lines.slope[0] = slope
|
|
92
|
+
self.lines.intercept[0] = intercept
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class OLS_TransformationN(PeriodN):
|
|
96
|
+
"""
|
|
97
|
+
Calculates the ``zscore`` for data0 and data1. Although it doesn't directly
|
|
98
|
+
use any external package, it relies on ``OLS_SlopeInterceptN`` which uses
|
|
99
|
+
``pandas`` and ``statsmodels``
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
_mindatas = 2 # ensure at least 2 data feeds are passed
|
|
103
|
+
lines = (
|
|
104
|
+
"spread",
|
|
105
|
+
"spread_mean",
|
|
106
|
+
"spread_std",
|
|
107
|
+
"zscore",
|
|
108
|
+
)
|
|
109
|
+
params = (("period", 10),)
|
|
110
|
+
|
|
111
|
+
def __init__(self):
|
|
112
|
+
"""Initialize the OLS Transformation indicator.
|
|
113
|
+
|
|
114
|
+
Creates OLS slope-intercept indicator for transformation calculations.
|
|
115
|
+
"""
|
|
116
|
+
super().__init__()
|
|
117
|
+
self.slint = OLS_Slope_InterceptN(*self.datas)
|
|
118
|
+
|
|
119
|
+
def next(self):
|
|
120
|
+
"""Calculate OLS transformation values for the current bar.
|
|
121
|
+
|
|
122
|
+
Computes spread, mean, std, and zscore based on OLS regression.
|
|
123
|
+
"""
|
|
124
|
+
slope = self.slint.slope[0]
|
|
125
|
+
intercept = self.slint.intercept[0]
|
|
126
|
+
spread = self.data0[0] - (slope * self.data1[0] + intercept)
|
|
127
|
+
self.lines.spread[0] = spread
|
|
128
|
+
|
|
129
|
+
# Calculate spread_mean (SMA of spread)
|
|
130
|
+
period = self.p.period
|
|
131
|
+
spread_sum = spread
|
|
132
|
+
for i in range(1, period):
|
|
133
|
+
spread_sum += self.lines.spread[-i]
|
|
134
|
+
spread_mean = spread_sum / period
|
|
135
|
+
self.lines.spread_mean[0] = spread_mean
|
|
136
|
+
|
|
137
|
+
# Calculate spread_std (StdDev of spread)
|
|
138
|
+
var_sum = (spread - spread_mean) ** 2
|
|
139
|
+
for i in range(1, period):
|
|
140
|
+
var_sum += (self.lines.spread[-i] - spread_mean) ** 2
|
|
141
|
+
spread_std = (var_sum / period) ** 0.5
|
|
142
|
+
self.lines.spread_std[0] = spread_std
|
|
143
|
+
|
|
144
|
+
# Calculate zscore
|
|
145
|
+
if spread_std != 0:
|
|
146
|
+
self.lines.zscore[0] = (spread - spread_mean) / spread_std
|
|
147
|
+
else:
|
|
148
|
+
self.lines.zscore[0] = 0.0
|
|
149
|
+
|
|
150
|
+
def once(self, start, end):
|
|
151
|
+
"""Calculate OLS transformation in runonce mode.
|
|
152
|
+
|
|
153
|
+
Computes spread, mean, std, and zscore values across all bars.
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
slope_array = self.slint.lines.slope.array
|
|
157
|
+
intercept_array = self.slint.lines.intercept.array
|
|
158
|
+
d0_array = self.data0.array
|
|
159
|
+
d1_array = self.data1.array
|
|
160
|
+
spread_array = self.lines.spread.array
|
|
161
|
+
mean_array = self.lines.spread_mean.array
|
|
162
|
+
std_array = self.lines.spread_std.array
|
|
163
|
+
zscore_array = self.lines.zscore.array
|
|
164
|
+
period = self.p.period
|
|
165
|
+
|
|
166
|
+
for arr in [spread_array, mean_array, std_array, zscore_array]:
|
|
167
|
+
while len(arr) < end:
|
|
168
|
+
arr.append(float("nan"))
|
|
169
|
+
|
|
170
|
+
# Calculate spread
|
|
171
|
+
for i in range(
|
|
172
|
+
start, min(end, len(slope_array), len(intercept_array), len(d0_array), len(d1_array))
|
|
173
|
+
):
|
|
174
|
+
slope = slope_array[i] if i < len(slope_array) else 0.0
|
|
175
|
+
intercept = intercept_array[i] if i < len(intercept_array) else 0.0
|
|
176
|
+
d0 = d0_array[i] if i < len(d0_array) else 0.0
|
|
177
|
+
d1 = d1_array[i] if i < len(d1_array) else 0.0
|
|
178
|
+
spread_array[i] = d0 - (slope * d1 + intercept)
|
|
179
|
+
|
|
180
|
+
# Calculate spread_mean, spread_std, zscore
|
|
181
|
+
for i in range(start, min(end, len(spread_array))):
|
|
182
|
+
if i < period - 1:
|
|
183
|
+
mean_array[i] = float("nan")
|
|
184
|
+
std_array[i] = float("nan")
|
|
185
|
+
zscore_array[i] = float("nan")
|
|
186
|
+
else:
|
|
187
|
+
spread_sum = 0.0
|
|
188
|
+
for j in range(period):
|
|
189
|
+
idx = i - j
|
|
190
|
+
if idx >= 0 and idx < len(spread_array):
|
|
191
|
+
spread_sum += spread_array[idx]
|
|
192
|
+
spread_mean = spread_sum / period
|
|
193
|
+
mean_array[i] = spread_mean
|
|
194
|
+
|
|
195
|
+
var_sum = 0.0
|
|
196
|
+
for j in range(period):
|
|
197
|
+
idx = i - j
|
|
198
|
+
if idx >= 0 and idx < len(spread_array):
|
|
199
|
+
var_sum += (spread_array[idx] - spread_mean) ** 2
|
|
200
|
+
spread_std = (var_sum / period) ** 0.5
|
|
201
|
+
std_array[i] = spread_std
|
|
202
|
+
|
|
203
|
+
spread = spread_array[i]
|
|
204
|
+
if spread_std != 0:
|
|
205
|
+
zscore_array[i] = (spread - spread_mean) / spread_std
|
|
206
|
+
else:
|
|
207
|
+
zscore_array[i] = 0.0
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class OLS_BetaN(PeriodN):
|
|
211
|
+
"""
|
|
212
|
+
Calculates a regression of data1 on data0 using ``pandas.ols``
|
|
213
|
+
|
|
214
|
+
Uses ``pandas``
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
_mindatas = 2 # ensure at least 2 data feeds are passed
|
|
218
|
+
|
|
219
|
+
packages = (("pandas", "pd"),)
|
|
220
|
+
|
|
221
|
+
lines = ("beta",)
|
|
222
|
+
params = (("period", 10),)
|
|
223
|
+
|
|
224
|
+
def next(self):
|
|
225
|
+
"""Calculate beta via OLS regression for the current bar.
|
|
226
|
+
|
|
227
|
+
Uses pandas OLS to calculate regression beta.
|
|
228
|
+
"""
|
|
229
|
+
y, x = (pd.Series(d.get(size=self.p.period)) for d in self.datas)
|
|
230
|
+
r_beta = pd.ols(y=y, x=x, window_type="full_sample")
|
|
231
|
+
self.lines.beta[0] = r_beta.beta["x"]
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class CointN(PeriodN):
|
|
235
|
+
"""
|
|
236
|
+
Calculates the score (coint_t) and pvalue for a given ``period`` for the
|
|
237
|
+
data feeds
|
|
238
|
+
|
|
239
|
+
Uses ``pandas`` and ``statsmodels`` (for ``coint``)
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
_mindatas = 2 # ensure at least 2 data feeds are passed
|
|
243
|
+
|
|
244
|
+
packages = (("pandas", "pd"),) # import pandas as pd
|
|
245
|
+
frompackages = (("statsmodels.tsa.stattools", "coint"),) # from st... import coint
|
|
246
|
+
|
|
247
|
+
lines = (
|
|
248
|
+
"score",
|
|
249
|
+
"pvalue",
|
|
250
|
+
)
|
|
251
|
+
params = (
|
|
252
|
+
("period", 10),
|
|
253
|
+
("trend", "c"), # see statsmodel.tsa.statttools
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
def next(self):
|
|
257
|
+
"""Calculate cointegration test for the current period.
|
|
258
|
+
|
|
259
|
+
Uses statsmodels coint function to test for cointegration.
|
|
260
|
+
"""
|
|
261
|
+
coint = _get_coint()
|
|
262
|
+
x, y = (pd.Series(d.get(size=self.p.period)) for d in self.datas)
|
|
263
|
+
score, pvalue, _ = coint(x, y, trend=self.p.trend)
|
|
264
|
+
self.lines.score[0] = score
|
|
265
|
+
self.lines.pvalue[0] = pvalue
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Oscillator Indicator Module - Oscillating indicators.
|
|
3
|
+
|
|
4
|
+
This module provides oscillator indicators that show the deviation
|
|
5
|
+
of one data series from another, typically price from a moving average.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
OscillatorMixIn: MixIn class to create oscillating indicators.
|
|
9
|
+
Oscillator: Oscillation of data around another data.
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
class MyStrategy(bt.Strategy):
|
|
13
|
+
def __init__(self):
|
|
14
|
+
# Oscillate price around SMA
|
|
15
|
+
self.osc = bt.indicators.Oscillator(self.data, bt.indicators.SMA(self.data, period=20))
|
|
16
|
+
|
|
17
|
+
def next(self):
|
|
18
|
+
# When oscillator is positive, price is above SMA
|
|
19
|
+
if self.osc[0] > 0:
|
|
20
|
+
self.buy()
|
|
21
|
+
elif self.osc[0] < 0:
|
|
22
|
+
self.sell()
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import sys
|
|
26
|
+
|
|
27
|
+
from ..utils.log_message import get_logger
|
|
28
|
+
from . import Indicator, MovingAverage
|
|
29
|
+
|
|
30
|
+
logger = get_logger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class OscillatorMixIn(Indicator):
|
|
34
|
+
"""
|
|
35
|
+
MixIn class to create a subclass with another indicator. The main line of
|
|
36
|
+
that indicator will be substracted from the other base class main line
|
|
37
|
+
creating an oscillator
|
|
38
|
+
|
|
39
|
+
The usage is:
|
|
40
|
+
|
|
41
|
+
- Class XXXOscillator(XXX, OscillatorMixIn)
|
|
42
|
+
|
|
43
|
+
Formula:
|
|
44
|
+
- XXX calculates lines[0]
|
|
45
|
+
- osc = self.data - XXX.lines[0]
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
plotlines = {"_0": {"_name": "osc"}}
|
|
49
|
+
|
|
50
|
+
def _plotinit(self):
|
|
51
|
+
try:
|
|
52
|
+
lname = self.lines._getlinealias(0)
|
|
53
|
+
self.plotlines._0._name = lname + "_osc"
|
|
54
|
+
except AttributeError:
|
|
55
|
+
# No line alias available; keep the default plot label.
|
|
56
|
+
logger.debug("oscillator:55 ignored AttributeError")
|
|
57
|
+
|
|
58
|
+
def __init__(self):
|
|
59
|
+
"""Initialize the oscillator by subtracting the base line from data."""
|
|
60
|
+
self.lines[0] = self.data - self.lines[0]
|
|
61
|
+
super().__init__()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Oscillator(Indicator):
|
|
65
|
+
"""
|
|
66
|
+
Oscillation of given data around another data
|
|
67
|
+
|
|
68
|
+
Datas:
|
|
69
|
+
This indicator can accept one or two data for the calculation.
|
|
70
|
+
|
|
71
|
+
- If one data is provided, it must be a complex "Lines" object (indicator)
|
|
72
|
+
which also has "data".Example: A moving average
|
|
73
|
+
|
|
74
|
+
The calculated oscillation will be that of the Moving Average (in the
|
|
75
|
+
example) around the data that was used for the average calculation
|
|
76
|
+
|
|
77
|
+
- If two data are provided, the calculated oscillation will be that of the
|
|
78
|
+
second data around the first data
|
|
79
|
+
|
|
80
|
+
Formula:
|
|
81
|
+
- 1 data -> osc = data.data - data
|
|
82
|
+
- 2 datas -> osc = data0 - data1
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
lines = ("osc",)
|
|
86
|
+
|
|
87
|
+
# Have a default value which can be later modified if needed
|
|
88
|
+
plotlines = {"_0": {"_name": "osc"}}
|
|
89
|
+
|
|
90
|
+
def _plotinit(self):
|
|
91
|
+
try:
|
|
92
|
+
lname = self.dataosc._getlinealias(0)
|
|
93
|
+
self.plotlines._0._name = lname + "_osc"
|
|
94
|
+
except AttributeError:
|
|
95
|
+
# No line alias available; keep the default plot label.
|
|
96
|
+
logger.debug("oscillator:95 ignored AttributeError")
|
|
97
|
+
|
|
98
|
+
def __init__(self):
|
|
99
|
+
"""Initialize the oscillator with data source and oscillator data.
|
|
100
|
+
|
|
101
|
+
Calculates the oscillation between two data series or between
|
|
102
|
+
a data series and its underlying data.
|
|
103
|
+
"""
|
|
104
|
+
super().__init__()
|
|
105
|
+
|
|
106
|
+
if len(self.datas) > 1:
|
|
107
|
+
datasrc = self.data
|
|
108
|
+
self.dataosc = self.data1
|
|
109
|
+
else:
|
|
110
|
+
datasrc = self.data.data
|
|
111
|
+
self.dataosc = self.data
|
|
112
|
+
|
|
113
|
+
self.lines[0] = datasrc - self.dataosc
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# Automatic creation of Oscillating Lines
|
|
117
|
+
|
|
118
|
+
for movav in MovingAverage._movavs[0:]:
|
|
119
|
+
_newclsdoc = """
|
|
120
|
+
Oscillation of a %s around its data
|
|
121
|
+
"""
|
|
122
|
+
# Skip aliases - they will be created automatically
|
|
123
|
+
if getattr(movav, "aliased", ""):
|
|
124
|
+
continue
|
|
125
|
+
|
|
126
|
+
movname = movav.__name__
|
|
127
|
+
# Handle both tuple lines and Lines objects after refactoring
|
|
128
|
+
if hasattr(movav.lines, "_getlinealias"):
|
|
129
|
+
# It's a Lines object
|
|
130
|
+
linename = movav.lines._getlinealias(0)
|
|
131
|
+
elif isinstance(movav.lines, (tuple, list)) and movav.lines:
|
|
132
|
+
# It's a tuple/list of line names
|
|
133
|
+
linename = movav.lines[0]
|
|
134
|
+
else:
|
|
135
|
+
# Fallback to first line name or class name. The lambda is invoked
|
|
136
|
+
# immediately within this loop iteration (no late binding), so B023 is
|
|
137
|
+
# a false positive here.
|
|
138
|
+
linename = (
|
|
139
|
+
getattr(movav.lines, "_getlinealias", lambda x: movav.__name__.lower())(0) # noqa: B023
|
|
140
|
+
if hasattr(movav.lines, "_getlinealias")
|
|
141
|
+
else movav.__name__.lower()
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
newclsname = movname + "Oscillator"
|
|
145
|
+
|
|
146
|
+
newaliases = [movname + "Osc"]
|
|
147
|
+
for alias in getattr(movav, "alias", []):
|
|
148
|
+
for suffix in ["Oscillator", "Osc"]:
|
|
149
|
+
newaliases.append(alias + suffix)
|
|
150
|
+
|
|
151
|
+
newclsdoc = _newclsdoc % movname
|
|
152
|
+
newclsdct = {
|
|
153
|
+
"__doc__": newclsdoc,
|
|
154
|
+
"__module__": OscillatorMixIn.__module__,
|
|
155
|
+
"_notregister": True,
|
|
156
|
+
"alias": newaliases,
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
newcls = type(str(newclsname), (movav, OscillatorMixIn), newclsdct)
|
|
160
|
+
module = sys.modules[OscillatorMixIn.__module__]
|
|
161
|
+
setattr(module, newclsname, newcls)
|