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,834 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Basic Operations Indicator Module - Fundamental calculation indicators.
|
|
3
|
+
|
|
4
|
+
This module provides basic mathematical operations and calculations for
|
|
5
|
+
indicator development, including period-based operations and statistics.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
PeriodN: Base class for period-based indicators.
|
|
9
|
+
OperationN: Base class for function-based period calculations.
|
|
10
|
+
BaseApplyN: Base class for applying a function over a period.
|
|
11
|
+
ApplyN: Applies a function over a period.
|
|
12
|
+
Highest: Calculates highest value (alias: MaxN).
|
|
13
|
+
Lowest: Calculates lowest value (alias: MinN).
|
|
14
|
+
ReduceN: Applies reduce function over a period.
|
|
15
|
+
SumN: Calculates sum over a period.
|
|
16
|
+
AnyN: Returns True if any value is True.
|
|
17
|
+
AllN: Returns True only if all values are True.
|
|
18
|
+
FindFirstIndex: Finds first index matching condition.
|
|
19
|
+
FindFirstIndexHighest: Index of first highest value.
|
|
20
|
+
FindFirstIndexLowest: Index of first lowest value.
|
|
21
|
+
FindLastIndex: Finds last index matching condition.
|
|
22
|
+
FindLastIndexHighest: Index of last highest value.
|
|
23
|
+
FindLastIndexLowest: Index of last lowest value.
|
|
24
|
+
Accum: Cumulative sum (aliases: CumSum, CumulativeSum).
|
|
25
|
+
Average: Arithmetic mean (aliases: ArithmeticMean, Mean).
|
|
26
|
+
ExponentialSmoothing: EMA-style smoothing (alias: ExpSmoothing).
|
|
27
|
+
ExponentialSmoothingDynamic: Dynamic alpha smoothing (alias: ExpSmoothingDynamic).
|
|
28
|
+
WeightedAverage: Weighted average (alias: AverageWeighted).
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
class MyStrategy(bt.Strategy):
|
|
32
|
+
def __init__(self):
|
|
33
|
+
# Calculate highest and lowest prices over 20 periods
|
|
34
|
+
self.highest = bt.indicators.Highest(self.data.close, period=20)
|
|
35
|
+
self.lowest = bt.indicators.Lowest(self.data.close, period=20)
|
|
36
|
+
|
|
37
|
+
# Calculate average price
|
|
38
|
+
self.avg = bt.indicators.Average(self.data.close, period=20)
|
|
39
|
+
|
|
40
|
+
def next(self):
|
|
41
|
+
# Buy when price breaks above highest of last 20 bars
|
|
42
|
+
if self.data.close[0] > self.highest[-1]:
|
|
43
|
+
self.buy()
|
|
44
|
+
|
|
45
|
+
# Sell when price breaks below lowest of last 20 bars
|
|
46
|
+
elif self.data.close[0] < self.lowest[-1]:
|
|
47
|
+
self.sell()
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
import functools
|
|
51
|
+
import math
|
|
52
|
+
import operator
|
|
53
|
+
|
|
54
|
+
from ..utils.log_message import get_logger
|
|
55
|
+
from ..utils.py3 import map, range
|
|
56
|
+
from . import Indicator
|
|
57
|
+
|
|
58
|
+
logger = get_logger(__name__)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class PeriodN(Indicator):
|
|
62
|
+
"""
|
|
63
|
+
Base class for indicators which take a period (__init__ has to be called
|
|
64
|
+
either via supper or explicitly)
|
|
65
|
+
|
|
66
|
+
This class has no defined lines
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
params = (("period", 1),)
|
|
70
|
+
|
|
71
|
+
def __init__(self):
|
|
72
|
+
"""Initialize the period-based indicator.
|
|
73
|
+
|
|
74
|
+
Sets minimum period based on the period parameter.
|
|
75
|
+
"""
|
|
76
|
+
super().__init__()
|
|
77
|
+
self.addminperiod(self.p.period)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# Calculate data for past N periods using func, func is a callable function
|
|
81
|
+
class OperationN(PeriodN):
|
|
82
|
+
"""
|
|
83
|
+
Calculates "func" for a given period
|
|
84
|
+
|
|
85
|
+
Serves as a base for classes that work with a period and can express the
|
|
86
|
+
logic in a callable object
|
|
87
|
+
|
|
88
|
+
Note:
|
|
89
|
+
Base classes must provide a "func" attribute which is callable
|
|
90
|
+
|
|
91
|
+
Formula:
|
|
92
|
+
- line = func(data, period)
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
def next(self):
|
|
96
|
+
"""Calculate function value for the current bar.
|
|
97
|
+
|
|
98
|
+
Applies func to the last 'period' data values.
|
|
99
|
+
"""
|
|
100
|
+
# CRITICAL FIX: Use proper line assignment instead of direct array manipulation
|
|
101
|
+
# The line[0] assignment will handle the buffer correctly
|
|
102
|
+
window = self.data.get(size=self.p.period)
|
|
103
|
+
if len(window) < self.p.period:
|
|
104
|
+
try:
|
|
105
|
+
window = [self.data[i] for i in range(-self.p.period + 1, 1)]
|
|
106
|
+
except (IndexError, TypeError):
|
|
107
|
+
window = ()
|
|
108
|
+
|
|
109
|
+
if len(window) < self.p.period:
|
|
110
|
+
self.lines[0][0] = float("nan")
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
value = self.func(window)
|
|
114
|
+
self.lines[0][0] = value
|
|
115
|
+
|
|
116
|
+
def once(self, start, end):
|
|
117
|
+
"""Optimized batch calculation for runonce mode - same approach as SMA"""
|
|
118
|
+
try:
|
|
119
|
+
# Get arrays for efficient calculation - use same approach as SMA
|
|
120
|
+
dst = self.lines[0].array
|
|
121
|
+
src = self.data.array
|
|
122
|
+
period = self.p.period
|
|
123
|
+
func = self.func
|
|
124
|
+
|
|
125
|
+
# CRITICAL FIX: Handle case where start >= end (not enough data for this indicator)
|
|
126
|
+
# This can happen when nested indicators have larger minperiod than available data
|
|
127
|
+
if start >= end:
|
|
128
|
+
# Still need to pre-fill the array with NaN
|
|
129
|
+
while len(dst) < end:
|
|
130
|
+
dst.append(float("nan"))
|
|
131
|
+
return # No data to process
|
|
132
|
+
|
|
133
|
+
# CRITICAL FIX: Pre-fill warmup period with NaN instead of 0.0
|
|
134
|
+
# This ensures that accessing indicator values before minperiod returns nan
|
|
135
|
+
# instead of 0.0, which could trigger incorrect buy/sell signals
|
|
136
|
+
while len(dst) < end:
|
|
137
|
+
dst.append(float("nan"))
|
|
138
|
+
|
|
139
|
+
# Calculate for each index from start to end
|
|
140
|
+
for i in range(start, end):
|
|
141
|
+
if i >= period - 1:
|
|
142
|
+
# Calculate SMA-style: get last 'period' values
|
|
143
|
+
start_idx = i - period + 1
|
|
144
|
+
end_idx = i + 1
|
|
145
|
+
if end_idx <= len(src):
|
|
146
|
+
# Get slice of data
|
|
147
|
+
slice_data = src[start_idx:end_idx]
|
|
148
|
+
# Apply function (min, max, etc.)
|
|
149
|
+
if len(slice_data) == period:
|
|
150
|
+
try:
|
|
151
|
+
result = func(slice_data)
|
|
152
|
+
dst[i] = float(result) if result is not None else float("nan")
|
|
153
|
+
except (ValueError, TypeError):
|
|
154
|
+
dst[i] = float("nan")
|
|
155
|
+
else:
|
|
156
|
+
dst[i] = float("nan")
|
|
157
|
+
else:
|
|
158
|
+
dst[i] = float("nan")
|
|
159
|
+
else:
|
|
160
|
+
# Not enough data yet
|
|
161
|
+
dst[i] = float("nan")
|
|
162
|
+
except Exception:
|
|
163
|
+
logger.debug("OperationN.once() failed, falling back to once_via_next", exc_info=True)
|
|
164
|
+
# Fallback to once_via_next if once() fails
|
|
165
|
+
super().once_via_next(start, end)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# Set callable function when calculating indicators
|
|
169
|
+
class BaseApplyN(OperationN):
|
|
170
|
+
"""
|
|
171
|
+
Base class for ApplyN and others which may take a ``func`` as a parameter
|
|
172
|
+
but want to define the lines in the indicator.
|
|
173
|
+
|
|
174
|
+
Calculates ``func`` for a given period where func is given as a parameter,
|
|
175
|
+
aka named argument or ``kwarg``
|
|
176
|
+
|
|
177
|
+
Formula:
|
|
178
|
+
- lines[0] = func(data, period)
|
|
179
|
+
|
|
180
|
+
Any extra lines defined beyond the first (index 0) are not calculated
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
params = (("func", None),)
|
|
184
|
+
|
|
185
|
+
def __init__(self):
|
|
186
|
+
"""Initialize the base apply indicator.
|
|
187
|
+
|
|
188
|
+
Sets func from parameter and initializes parent.
|
|
189
|
+
"""
|
|
190
|
+
self.func = self.p.func
|
|
191
|
+
super().__init__()
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
# Calculate specific line based on the set callable function
|
|
195
|
+
class ApplyN(BaseApplyN):
|
|
196
|
+
"""
|
|
197
|
+
Calculates ``func`` for a given period
|
|
198
|
+
|
|
199
|
+
Formula:
|
|
200
|
+
- line = func(data, period)
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
lines = ("apply",)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
# Calculate highest price in past N periods
|
|
207
|
+
class Highest(OperationN):
|
|
208
|
+
"""
|
|
209
|
+
Calculates the highest value for the data in a given period
|
|
210
|
+
|
|
211
|
+
Uses the built-in ``max`` for the calculation
|
|
212
|
+
|
|
213
|
+
Formula:
|
|
214
|
+
- highest = max(data, period)
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
alias = ("MaxN",)
|
|
218
|
+
lines = ("highest",)
|
|
219
|
+
func = max
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
# Calculate lowest price in past N periods
|
|
223
|
+
class Lowest(OperationN):
|
|
224
|
+
"""
|
|
225
|
+
Calculates the lowest value for the data in a given period
|
|
226
|
+
|
|
227
|
+
Uses the built-in ``min`` for the calculation
|
|
228
|
+
|
|
229
|
+
Formula:
|
|
230
|
+
- lowest = min(data, period)
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
alias = ("MinN",)
|
|
234
|
+
lines = ("lowest",)
|
|
235
|
+
func = min
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# Mimic Python's reduce functionality
|
|
239
|
+
class ReduceN(OperationN):
|
|
240
|
+
"""
|
|
241
|
+
Calculates the Reduced value of the ``period`` data points applying
|
|
242
|
+
``function``
|
|
243
|
+
|
|
244
|
+
Uses the built-in ``reduce`` for the calculation plus the ``func`` that
|
|
245
|
+
subclassess define
|
|
246
|
+
|
|
247
|
+
Formula:
|
|
248
|
+
- reduced = reduce (function(data, period)), initializer=initializer)
|
|
249
|
+
|
|
250
|
+
Notes:
|
|
251
|
+
|
|
252
|
+
- In order to mimic the python `reduce`, this indicator takes a
|
|
253
|
+
``function`` non-named argument as the 1st argument, unlike other
|
|
254
|
+
Indicators which take only named arguments
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
lines = ("reduced",)
|
|
258
|
+
func = functools.reduce
|
|
259
|
+
|
|
260
|
+
def __init__(self, function, **kwargs):
|
|
261
|
+
"""Initialize the ReduceN indicator.
|
|
262
|
+
|
|
263
|
+
Sets up reduce function with optional initializer.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
function: The reduce function to apply.
|
|
267
|
+
**kwargs: Optional 'initializer' parameter.
|
|
268
|
+
"""
|
|
269
|
+
if "initializer" not in kwargs:
|
|
270
|
+
self.func = functools.partial(self.func, function)
|
|
271
|
+
else:
|
|
272
|
+
self.func = functools.partial(self.func, function, initializer=kwargs["initializer"])
|
|
273
|
+
|
|
274
|
+
super().__init__()
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
# Calculate sum of past N periods
|
|
278
|
+
class SumN(OperationN):
|
|
279
|
+
"""
|
|
280
|
+
Calculates the Sum of the data values over a given period
|
|
281
|
+
|
|
282
|
+
Uses ``math.fsum`` for the calculation rather than the built-in ``sum`` to
|
|
283
|
+
avoid precision errors
|
|
284
|
+
|
|
285
|
+
Formula:
|
|
286
|
+
- sumn = sum(data, period)
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
lines = ("sumn",)
|
|
290
|
+
func = math.fsum
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
# Return True if any value in past N periods is True
|
|
294
|
+
class AnyN(OperationN):
|
|
295
|
+
"""
|
|
296
|
+
Has a value of ``True`` (stored as ``1.0`` in the lines) if *any* of the
|
|
297
|
+
values in the ``period`` evaluates to non-zero (ie: ``True``)
|
|
298
|
+
|
|
299
|
+
Uses the built-in `any` for the calculation
|
|
300
|
+
|
|
301
|
+
Formula:
|
|
302
|
+
- anyn = any(data, period)
|
|
303
|
+
"""
|
|
304
|
+
|
|
305
|
+
lines = ("anyn",)
|
|
306
|
+
func = any
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
# Return True only if all values in past N periods are True
|
|
310
|
+
class AllN(OperationN):
|
|
311
|
+
"""
|
|
312
|
+
Has a value of ``True`` (stored as ``1.0`` in the lines) if *all* of the
|
|
313
|
+
values in the ``period`` evaluates to non-zero (ie: ``True``)
|
|
314
|
+
|
|
315
|
+
Uses the built-in `all` for the calculation
|
|
316
|
+
|
|
317
|
+
Formula:
|
|
318
|
+
- alln = all(data, period)
|
|
319
|
+
"""
|
|
320
|
+
|
|
321
|
+
lines = ("alln",)
|
|
322
|
+
func = all
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
# Return the first data point that satisfies the condition
|
|
326
|
+
class FindFirstIndex(OperationN):
|
|
327
|
+
"""
|
|
328
|
+
Returns the index of the last data that satisfies equality with the
|
|
329
|
+
condition generated by the parameter _evalfunc
|
|
330
|
+
|
|
331
|
+
Note:
|
|
332
|
+
Returned indexes look backwards. 0 is the current index and 1 is
|
|
333
|
+
the previous bar.
|
|
334
|
+
|
|
335
|
+
Formula:
|
|
336
|
+
- index = first for which data[index] == _evalfunc(data)
|
|
337
|
+
"""
|
|
338
|
+
|
|
339
|
+
lines = ("index",)
|
|
340
|
+
params = (("_evalfunc", None),)
|
|
341
|
+
|
|
342
|
+
def func(self, iterable):
|
|
343
|
+
"""Find first index where value matches eval function result.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
iterable: Data values to search.
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
Index of first matching value (looking backwards).
|
|
350
|
+
"""
|
|
351
|
+
m = self.p._evalfunc(iterable)
|
|
352
|
+
return next(i for i, v in enumerate(reversed(iterable)) if v == m)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
# Get the earliest occurrence of the highest price in the past
|
|
356
|
+
class FindFirstIndexHighest(FindFirstIndex):
|
|
357
|
+
"""
|
|
358
|
+
Returns the index of the first data that is the highest in the period
|
|
359
|
+
|
|
360
|
+
Note:
|
|
361
|
+
Returned indexes look backwards. 0 is the current index and 1 is
|
|
362
|
+
the previous bar.
|
|
363
|
+
|
|
364
|
+
Formula:
|
|
365
|
+
- index = index of first data which is the highest
|
|
366
|
+
"""
|
|
367
|
+
|
|
368
|
+
params = (("_evalfunc", max),)
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
# Get the earliest occurrence of the lowest price in the past
|
|
372
|
+
class FindFirstIndexLowest(FindFirstIndex):
|
|
373
|
+
"""
|
|
374
|
+
Returns the index of the first data that is the lowest in the period
|
|
375
|
+
|
|
376
|
+
Note:
|
|
377
|
+
Returned indexes look backwards. 0 is the current index and 1 is
|
|
378
|
+
the previous bar.
|
|
379
|
+
|
|
380
|
+
Formula:
|
|
381
|
+
- index = index of first data which is the lowest
|
|
382
|
+
"""
|
|
383
|
+
|
|
384
|
+
params = (("_evalfunc", min),)
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
# Get the index of the last data point that satisfies the condition
|
|
388
|
+
class FindLastIndex(OperationN):
|
|
389
|
+
"""
|
|
390
|
+
Returns the index of the last data that satisfies equality with the
|
|
391
|
+
condition generated by the parameter _evalfunc
|
|
392
|
+
|
|
393
|
+
Note:
|
|
394
|
+
Returned indexes look backwards. 0 is the current index and 1 is
|
|
395
|
+
the previous bar.
|
|
396
|
+
|
|
397
|
+
Formula:
|
|
398
|
+
- index = last for which data[index] == _evalfunc(data)
|
|
399
|
+
"""
|
|
400
|
+
|
|
401
|
+
lines = ("index",)
|
|
402
|
+
params = (("_evalfunc", None),)
|
|
403
|
+
|
|
404
|
+
def func(self, iterable):
|
|
405
|
+
"""Find last index where value matches eval function result.
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
iterable: Data values to search.
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
Index of last matching value (looking backwards).
|
|
412
|
+
"""
|
|
413
|
+
m = self.p._evalfunc(iterable)
|
|
414
|
+
index = next(i for i, v in enumerate(iterable) if v == m)
|
|
415
|
+
# The iterable goes from 0 -> period - 1. If the last element
|
|
416
|
+
# which is the current bar is returned and without the -1 then
|
|
417
|
+
# period - index = 1 ... and must be zero!
|
|
418
|
+
return self.p.period - index - 1
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
# Get the latest occurrence of the highest price in the past
|
|
422
|
+
class FindLastIndexHighest(FindLastIndex):
|
|
423
|
+
"""
|
|
424
|
+
Returns the index of the last data that is the highest in the period
|
|
425
|
+
|
|
426
|
+
Note:
|
|
427
|
+
Returned indexes look backwards. 0 is the current index and 1 is
|
|
428
|
+
the previous bar.
|
|
429
|
+
|
|
430
|
+
Formula:
|
|
431
|
+
- index = index of last data which is the highest
|
|
432
|
+
"""
|
|
433
|
+
|
|
434
|
+
params = (("_evalfunc", max),)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
# Get the latest occurrence of the lowest price in the past
|
|
438
|
+
class FindLastIndexLowest(FindLastIndex):
|
|
439
|
+
"""
|
|
440
|
+
Returns the index of the last data that is the lowest in the period
|
|
441
|
+
|
|
442
|
+
Note:
|
|
443
|
+
Returned indexes look backwards. 0 is the current index and 1 is
|
|
444
|
+
the previous bar.
|
|
445
|
+
|
|
446
|
+
Formula:
|
|
447
|
+
- index = index of last data which is the lowest
|
|
448
|
+
"""
|
|
449
|
+
|
|
450
|
+
params = (("_evalfunc", min),)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
# Calculate cumulative sum
|
|
454
|
+
class Accum(Indicator):
|
|
455
|
+
"""
|
|
456
|
+
Cummulative sum of the data values
|
|
457
|
+
|
|
458
|
+
Formula:
|
|
459
|
+
- accum += data
|
|
460
|
+
"""
|
|
461
|
+
|
|
462
|
+
alias = (
|
|
463
|
+
"CumSum",
|
|
464
|
+
"CumulativeSum",
|
|
465
|
+
)
|
|
466
|
+
lines = ("accum",)
|
|
467
|
+
params = (("seed", 0.0),)
|
|
468
|
+
|
|
469
|
+
# xxxstart methods use the seed (starting value) and passed data to
|
|
470
|
+
# construct the first value keeping the minperiod to 1 since no
|
|
471
|
+
# initial look-back value is needed
|
|
472
|
+
|
|
473
|
+
def nextstart(self):
|
|
474
|
+
"""Start accumulation with seed value.
|
|
475
|
+
|
|
476
|
+
accum = seed + data[0]
|
|
477
|
+
"""
|
|
478
|
+
self.lines[0][0] = self.p.seed + self.data[0]
|
|
479
|
+
|
|
480
|
+
def next(self):
|
|
481
|
+
"""Add current data value to accumulation.
|
|
482
|
+
|
|
483
|
+
accum += data
|
|
484
|
+
"""
|
|
485
|
+
self.lines[0][0] = self.lines[0][-1] + self.data[0]
|
|
486
|
+
|
|
487
|
+
def oncestart(self, start, end):
|
|
488
|
+
"""Start accumulation in runonce mode.
|
|
489
|
+
|
|
490
|
+
accum = seed + data for each bar.
|
|
491
|
+
"""
|
|
492
|
+
dst = self.lines[0].array
|
|
493
|
+
src = self.data.array
|
|
494
|
+
prev = self.p.seed
|
|
495
|
+
|
|
496
|
+
for i in range(start, end):
|
|
497
|
+
dst[i] = prev = prev + src[i]
|
|
498
|
+
|
|
499
|
+
def once(self, start, end):
|
|
500
|
+
"""Continue accumulation in runonce mode.
|
|
501
|
+
|
|
502
|
+
accum = prev_accum + data for each bar.
|
|
503
|
+
"""
|
|
504
|
+
dst = self.lines[0].array
|
|
505
|
+
src = self.data.array
|
|
506
|
+
prev = dst[start - 1]
|
|
507
|
+
|
|
508
|
+
for i in range(start, end):
|
|
509
|
+
dst[i] = prev = prev + src[i]
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
# Calculate arithmetic mean
|
|
513
|
+
class Average(PeriodN):
|
|
514
|
+
"""
|
|
515
|
+
Averages a given data arithmetically over a period
|
|
516
|
+
|
|
517
|
+
Formula:
|
|
518
|
+
- av = data(period) / period
|
|
519
|
+
|
|
520
|
+
See also:
|
|
521
|
+
- https://en.wikipedia.org/wiki/Arithmetic_mean
|
|
522
|
+
"""
|
|
523
|
+
|
|
524
|
+
alias = (
|
|
525
|
+
"ArithmeticMean",
|
|
526
|
+
"Mean",
|
|
527
|
+
)
|
|
528
|
+
lines = ("av",)
|
|
529
|
+
|
|
530
|
+
def next(self):
|
|
531
|
+
"""Calculate arithmetic mean for the current bar.
|
|
532
|
+
|
|
533
|
+
av = sum(data, period) / period
|
|
534
|
+
"""
|
|
535
|
+
data_values = self.data.get(size=self.p.period)
|
|
536
|
+
avg_value = math.fsum(data_values) / self.p.period
|
|
537
|
+
self.lines[0][0] = avg_value
|
|
538
|
+
|
|
539
|
+
def once(self, start, end):
|
|
540
|
+
"""Calculate Average (SMA) in runonce mode"""
|
|
541
|
+
src = self.data.array
|
|
542
|
+
dst = self.lines[0].array
|
|
543
|
+
period = self.p.period
|
|
544
|
+
|
|
545
|
+
# Ensure destination array is large enough
|
|
546
|
+
while len(dst) < end:
|
|
547
|
+
dst.append(float("nan"))
|
|
548
|
+
|
|
549
|
+
for i in range(start, end):
|
|
550
|
+
if i >= period - 1:
|
|
551
|
+
start_idx = i - period + 1
|
|
552
|
+
end_idx = i + 1
|
|
553
|
+
if end_idx <= len(src):
|
|
554
|
+
dst[i] = sum(src[start_idx:end_idx]) / period
|
|
555
|
+
else:
|
|
556
|
+
dst[i] = float("nan")
|
|
557
|
+
else:
|
|
558
|
+
dst[i] = float("nan")
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
# Calculate exponential moving average
|
|
562
|
+
class ExponentialSmoothing(Average):
|
|
563
|
+
"""
|
|
564
|
+
Averages a given data over a period using exponential smoothing
|
|
565
|
+
|
|
566
|
+
A regular ArithmeticMean (Average) is used as the seed value considering
|
|
567
|
+
the first period values of data
|
|
568
|
+
|
|
569
|
+
Formula:
|
|
570
|
+
- av = prev * (1 - alpha) + data * alpha
|
|
571
|
+
|
|
572
|
+
See also:
|
|
573
|
+
- https://en.wikipedia.org/wiki/Exponential_smoothing
|
|
574
|
+
"""
|
|
575
|
+
|
|
576
|
+
alias = ("ExpSmoothing",)
|
|
577
|
+
params = (("alpha", None),)
|
|
578
|
+
|
|
579
|
+
def __init__(self):
|
|
580
|
+
"""Initialize the exponential smoothing indicator.
|
|
581
|
+
|
|
582
|
+
Calculates alpha and alpha1 for smoothing calculation.
|
|
583
|
+
"""
|
|
584
|
+
self.alpha = self.p.alpha
|
|
585
|
+
if self.alpha is None:
|
|
586
|
+
self.alpha = 2.0 / (1.0 + self.p.period) # def EMA value
|
|
587
|
+
|
|
588
|
+
self.alpha1 = 1.0 - self.alpha
|
|
589
|
+
|
|
590
|
+
super().__init__()
|
|
591
|
+
|
|
592
|
+
def nextstart(self):
|
|
593
|
+
"""Seed exponential smoothing with SMA value.
|
|
594
|
+
|
|
595
|
+
Uses parent's SMA calculation for initial seed.
|
|
596
|
+
"""
|
|
597
|
+
# Fetch the seed value from the base class calculation
|
|
598
|
+
super().next()
|
|
599
|
+
|
|
600
|
+
def next(self):
|
|
601
|
+
"""Calculate EMA for the current bar.
|
|
602
|
+
|
|
603
|
+
av = prev * alpha1 + data * alpha
|
|
604
|
+
"""
|
|
605
|
+
self.lines[0][0] = self.lines[0][-1] * self.alpha1 + self.data[0] * self.alpha
|
|
606
|
+
|
|
607
|
+
def oncestart(self, start, end):
|
|
608
|
+
"""Calculate seed value in runonce mode.
|
|
609
|
+
|
|
610
|
+
Uses parent's SMA calculation for initial seed.
|
|
611
|
+
"""
|
|
612
|
+
# Calculate seed value using parent's once method (SMA of first period values)
|
|
613
|
+
# Call parent's once method to populate seed at index period-1
|
|
614
|
+
if start == self.p.period - 1:
|
|
615
|
+
super().once(start, end)
|
|
616
|
+
|
|
617
|
+
def once(self, start, end):
|
|
618
|
+
"""Calculate EMA in runonce mode"""
|
|
619
|
+
darray = self.data.array
|
|
620
|
+
larray = self.lines[0].array
|
|
621
|
+
alpha = self.alpha
|
|
622
|
+
alpha1 = self.alpha1
|
|
623
|
+
period = self.p.period
|
|
624
|
+
|
|
625
|
+
# CRITICAL FIX: Ensure array is properly sized
|
|
626
|
+
while len(larray) < end:
|
|
627
|
+
larray.append(float("nan"))
|
|
628
|
+
|
|
629
|
+
# CRITICAL FIX: Pre-fill warmup period with NaN to match expected behavior
|
|
630
|
+
# This prevents invalid comparisons during prenext when strategy calls next()
|
|
631
|
+
for i in range(0, min(period - 1, len(darray))):
|
|
632
|
+
larray[i] = float("nan")
|
|
633
|
+
|
|
634
|
+
# CRITICAL FIX: Calculate seed value (SMA of first period values)
|
|
635
|
+
# EMA starts at index period-1 with seed = SMA of first period values
|
|
636
|
+
seed_idx = period - 1
|
|
637
|
+
|
|
638
|
+
# Calculate seed as SMA of first period values
|
|
639
|
+
prev = None
|
|
640
|
+
if seed_idx < len(darray) and seed_idx >= 0:
|
|
641
|
+
seed_start = max(0, seed_idx - period + 1)
|
|
642
|
+
seed_end = seed_idx + 1
|
|
643
|
+
if seed_end <= len(darray) and seed_end > seed_start:
|
|
644
|
+
seed_data = darray[seed_start:seed_end]
|
|
645
|
+
if len(seed_data) >= period:
|
|
646
|
+
prev = sum(seed_data) / period
|
|
647
|
+
elif len(seed_data) > 0:
|
|
648
|
+
prev = sum(seed_data) / len(seed_data)
|
|
649
|
+
|
|
650
|
+
# Fallback: use first data point if seed calculation failed
|
|
651
|
+
if prev is None or (isinstance(prev, float) and math.isnan(prev)):
|
|
652
|
+
if len(darray) > 0:
|
|
653
|
+
prev = float(darray[0])
|
|
654
|
+
else:
|
|
655
|
+
prev = 0.0
|
|
656
|
+
|
|
657
|
+
# Set seed value at index period-1 if within calculation range
|
|
658
|
+
if seed_idx >= start and seed_idx < end:
|
|
659
|
+
larray[seed_idx] = prev
|
|
660
|
+
|
|
661
|
+
# Calculate EMA for indices from period to end
|
|
662
|
+
calc_start = max(start, period)
|
|
663
|
+
for i in range(calc_start, end):
|
|
664
|
+
if i < len(darray) and i >= 0:
|
|
665
|
+
# Use previous EMA value if available, otherwise use seed
|
|
666
|
+
if i > calc_start:
|
|
667
|
+
prev_ema = larray[i - 1]
|
|
668
|
+
if prev_ema > 0.0 and not (
|
|
669
|
+
isinstance(prev_ema, float) and math.isnan(prev_ema)
|
|
670
|
+
):
|
|
671
|
+
prev = prev_ema
|
|
672
|
+
|
|
673
|
+
# EMA formula: prev * alpha1 + current * alpha
|
|
674
|
+
current_val = float(darray[i])
|
|
675
|
+
prev = prev * alpha1 + current_val * alpha
|
|
676
|
+
larray[i] = prev
|
|
677
|
+
elif i >= len(darray):
|
|
678
|
+
break
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
class _Alpha1Line(Indicator):
|
|
682
|
+
"""Helper indicator to compute 1 - alpha dynamically.
|
|
683
|
+
|
|
684
|
+
Used by ExponentialSmoothingDynamic when alpha is a LineBuffer.
|
|
685
|
+
"""
|
|
686
|
+
|
|
687
|
+
lines = ("alpha1",)
|
|
688
|
+
params = (("alpha_source", None),)
|
|
689
|
+
|
|
690
|
+
def __init__(self):
|
|
691
|
+
"""Initialize with alpha source reference."""
|
|
692
|
+
self.alpha_source = self.p.alpha_source
|
|
693
|
+
super().__init__()
|
|
694
|
+
|
|
695
|
+
def next(self):
|
|
696
|
+
"""Calculate 1 - alpha for current bar."""
|
|
697
|
+
self.lines.alpha1[0] = 1.0 - self.alpha_source[0]
|
|
698
|
+
|
|
699
|
+
def once(self, start, end):
|
|
700
|
+
"""Calculate 1 - alpha in runonce mode."""
|
|
701
|
+
alpha_array = self.alpha_source.array
|
|
702
|
+
alpha1_array = self.lines.alpha1.array
|
|
703
|
+
for i in range(start, end):
|
|
704
|
+
alpha1_array[i] = 1.0 - alpha_array[i]
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
# Dynamic exponential moving average
|
|
708
|
+
class ExponentialSmoothingDynamic(ExponentialSmoothing):
|
|
709
|
+
"""
|
|
710
|
+
Averages a given data over a period using exponential smoothing
|
|
711
|
+
|
|
712
|
+
A regular ArithmeticMean (Average) is used as the seed value considering
|
|
713
|
+
the first period values of data
|
|
714
|
+
|
|
715
|
+
Note:
|
|
716
|
+
- alpha is an array of values which can be calculated dynamically
|
|
717
|
+
|
|
718
|
+
Formula:
|
|
719
|
+
- av = prev * (1 - alpha) + data * alpha
|
|
720
|
+
|
|
721
|
+
See also:
|
|
722
|
+
- https://en.wikipedia.org/wiki/Exponential_smoothing
|
|
723
|
+
"""
|
|
724
|
+
|
|
725
|
+
alias = ("ExpSmoothingDynamic",)
|
|
726
|
+
|
|
727
|
+
def __init__(self):
|
|
728
|
+
"""Initialize the dynamic exponential smoothing indicator.
|
|
729
|
+
|
|
730
|
+
Sets up alpha1 line for dynamic alpha values.
|
|
731
|
+
"""
|
|
732
|
+
super().__init__()
|
|
733
|
+
|
|
734
|
+
# CRITICAL FIX: Handle cases where alpha is a float instead of a LineBuffer
|
|
735
|
+
# The parent class sets self.alpha to a float value, but ExponentialSmoothingDynamic
|
|
736
|
+
# expects it to be a line-like object with _minperiod and array access
|
|
737
|
+
|
|
738
|
+
self._alpha_is_line = hasattr(self.alpha, "array")
|
|
739
|
+
|
|
740
|
+
if self._alpha_is_line:
|
|
741
|
+
# alpha is a LineBuffer or similar object
|
|
742
|
+
minperioddiff = max(0, self.alpha._minperiod - self.p.period)
|
|
743
|
+
self.lines[0].incminperiod(minperioddiff)
|
|
744
|
+
|
|
745
|
+
self.alpha1 = _Alpha1Line(alpha_source=self.alpha)
|
|
746
|
+
|
|
747
|
+
else:
|
|
748
|
+
# alpha is a float value - fall back to static smoothing
|
|
749
|
+
pass
|
|
750
|
+
|
|
751
|
+
def next(self):
|
|
752
|
+
"""Calculate dynamic EMA for the current bar.
|
|
753
|
+
|
|
754
|
+
Handles both float and LineBuffer alpha sources.
|
|
755
|
+
"""
|
|
756
|
+
alpha = self.alpha[0] if self._alpha_is_line else self.alpha
|
|
757
|
+
alpha1 = self.alpha1[0] if self._alpha_is_line else self.alpha1
|
|
758
|
+
self.lines[0][0] = self.lines[0][-1] * alpha1 + self.data[0] * alpha
|
|
759
|
+
|
|
760
|
+
def once(self, start, end):
|
|
761
|
+
"""Calculate dynamic EMA in runonce mode.
|
|
762
|
+
|
|
763
|
+
Handles both float and LineBuffer alpha sources.
|
|
764
|
+
"""
|
|
765
|
+
darray = self.data.array
|
|
766
|
+
larray = self.lines[0].array
|
|
767
|
+
|
|
768
|
+
alpha = self.alpha.array if self._alpha_is_line else self.alpha
|
|
769
|
+
alpha1 = self.alpha1.array if self._alpha_is_line else self.alpha1
|
|
770
|
+
|
|
771
|
+
prev = larray[start - 1]
|
|
772
|
+
for i in range(start, end):
|
|
773
|
+
alpha_i = alpha[i] if self._alpha_is_line else alpha
|
|
774
|
+
alpha1_i = alpha1[i] if self._alpha_is_line else alpha1
|
|
775
|
+
larray[i] = prev = prev * alpha1_i + darray[i] * alpha_i
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
# Calculate weighted moving average
|
|
779
|
+
class WeightedAverage(PeriodN):
|
|
780
|
+
"""
|
|
781
|
+
Calculates the weighted average of the given data over a period
|
|
782
|
+
|
|
783
|
+
The default weights (if none are provided) are linear to assigne more
|
|
784
|
+
weight to the most recent data
|
|
785
|
+
|
|
786
|
+
The result will be multiplied by a given "coef"
|
|
787
|
+
|
|
788
|
+
Formula:
|
|
789
|
+
- av = coef * sum(mul(data, period), weights)
|
|
790
|
+
|
|
791
|
+
See:
|
|
792
|
+
- https://en.wikipedia.org/wiki/Weighted_arithmetic_mean
|
|
793
|
+
"""
|
|
794
|
+
|
|
795
|
+
alias = ("AverageWeighted",)
|
|
796
|
+
lines = ("av",)
|
|
797
|
+
params: tuple = (
|
|
798
|
+
("coef", 1.0),
|
|
799
|
+
("weights", ()),
|
|
800
|
+
)
|
|
801
|
+
|
|
802
|
+
def __init__(self):
|
|
803
|
+
"""Initialize the Weighted Average indicator.
|
|
804
|
+
|
|
805
|
+
Sets up parameters for weighted average calculation.
|
|
806
|
+
"""
|
|
807
|
+
super().__init__()
|
|
808
|
+
|
|
809
|
+
def next(self):
|
|
810
|
+
"""Calculate weighted average for the current bar.
|
|
811
|
+
|
|
812
|
+
Multiplies data by weights and sums, then applies coefficient.
|
|
813
|
+
"""
|
|
814
|
+
data = self.data.get(size=self.p.period)
|
|
815
|
+
dataweighted = map(operator.mul, data, self.p.weights)
|
|
816
|
+
self.lines[0][0] = self.p.coef * math.fsum(dataweighted)
|
|
817
|
+
|
|
818
|
+
def once(self, start, end):
|
|
819
|
+
"""Calculate weighted average in runonce mode.
|
|
820
|
+
|
|
821
|
+
Computes weighted averages across all bars efficiently.
|
|
822
|
+
"""
|
|
823
|
+
darray = self.data.array
|
|
824
|
+
larray = self.line.array
|
|
825
|
+
period = self.p.period
|
|
826
|
+
coef = self.p.coef
|
|
827
|
+
weights = self.p.weights
|
|
828
|
+
|
|
829
|
+
for i in range(start, end):
|
|
830
|
+
data = darray[i - period + 1 : i + 1]
|
|
831
|
+
larray[i] = coef * math.fsum(map(operator.mul, data, weights))
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
AverageWeighted = WeightedAverage
|