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.
Files changed (465) hide show
  1. back_trader_python-1.4.0.dist-info/METADATA +1491 -0
  2. back_trader_python-1.4.0.dist-info/RECORD +465 -0
  3. back_trader_python-1.4.0.dist-info/WHEEL +5 -0
  4. back_trader_python-1.4.0.dist-info/licenses/LICENSE +674 -0
  5. back_trader_python-1.4.0.dist-info/top_level.txt +1 -0
  6. backtrader/__init__.py +148 -0
  7. backtrader/_cerebro/__init__.py +5 -0
  8. backtrader/_cerebro/channel.py +382 -0
  9. backtrader/_cerebro/execution.py +377 -0
  10. backtrader/_cerebro/lifecycle.py +143 -0
  11. backtrader/_cerebro/notifications.py +150 -0
  12. backtrader/_cerebro/presentation.py +230 -0
  13. backtrader/_cerebro/registry.py +593 -0
  14. backtrader/_cerebro/runnext.py +551 -0
  15. backtrader/_cerebro/runonce.py +142 -0
  16. backtrader/analyzer.py +594 -0
  17. backtrader/analyzers/__init__.py +50 -0
  18. backtrader/analyzers/annualreturn.py +226 -0
  19. backtrader/analyzers/calmar.py +165 -0
  20. backtrader/analyzers/drawdown.py +287 -0
  21. backtrader/analyzers/leverage.py +112 -0
  22. backtrader/analyzers/logreturnsrolling.py +190 -0
  23. backtrader/analyzers/periodstats.py +153 -0
  24. backtrader/analyzers/positions.py +119 -0
  25. backtrader/analyzers/pyfolio.py +470 -0
  26. backtrader/analyzers/returns.py +192 -0
  27. backtrader/analyzers/sharpe.py +307 -0
  28. backtrader/analyzers/sharpe_ratio_stats.py +534 -0
  29. backtrader/analyzers/sqn.py +112 -0
  30. backtrader/analyzers/timereturn.py +192 -0
  31. backtrader/analyzers/total_value.py +75 -0
  32. backtrader/analyzers/tradeanalyzer.py +278 -0
  33. backtrader/analyzers/transactions.py +141 -0
  34. backtrader/analyzers/vwr.py +245 -0
  35. backtrader/bokeh/__init__.py +155 -0
  36. backtrader/bokeh/analyzers/__init__.py +13 -0
  37. backtrader/bokeh/analyzers/plot.py +192 -0
  38. backtrader/bokeh/analyzers/recorder.py +181 -0
  39. backtrader/bokeh/app.py +1094 -0
  40. backtrader/bokeh/live/__init__.py +11 -0
  41. backtrader/bokeh/live/client.py +352 -0
  42. backtrader/bokeh/live/datahandler.py +346 -0
  43. backtrader/bokeh/plot_adapter.py +200 -0
  44. backtrader/bokeh/schemes/__init__.py +14 -0
  45. backtrader/bokeh/schemes/blackly.py +76 -0
  46. backtrader/bokeh/schemes/scheme.py +150 -0
  47. backtrader/bokeh/schemes/tradimo.py +82 -0
  48. backtrader/bokeh/tab.py +125 -0
  49. backtrader/bokeh/tabs/__init__.py +30 -0
  50. backtrader/bokeh/tabs/analyzer.py +120 -0
  51. backtrader/bokeh/tabs/config.py +154 -0
  52. backtrader/bokeh/tabs/live.py +109 -0
  53. backtrader/bokeh/tabs/log.py +185 -0
  54. backtrader/bokeh/tabs/metadata.py +182 -0
  55. backtrader/bokeh/tabs/performance.py +359 -0
  56. backtrader/bokeh/tabs/source.py +70 -0
  57. backtrader/bokeh/utils/__init__.py +8 -0
  58. backtrader/bokeh/utils/helpers.py +167 -0
  59. backtrader/bokeh/webapp.py +164 -0
  60. backtrader/broker.py +478 -0
  61. backtrader/brokers/__init__.py +36 -0
  62. backtrader/brokers/bbroker.py +2576 -0
  63. backtrader/brokers/btapibroker.py +8227 -0
  64. backtrader/brokers/hft/__init__.py +89 -0
  65. backtrader/brokers/hft/binance_bbo.py +625 -0
  66. backtrader/brokers/hft/binance_bbo_compare.py +1398 -0
  67. backtrader/brokers/hft/examples.py +1228 -0
  68. backtrader/brokers/hft/exchange.py +380 -0
  69. backtrader/brokers/hft/latency.py +309 -0
  70. backtrader/brokers/hft/matching_core.py +572 -0
  71. backtrader/brokers/hft/queue.py +238 -0
  72. backtrader/brokers/hft/recorder.py +88 -0
  73. backtrader/brokers/hft/state.py +138 -0
  74. backtrader/brokers/impact_models.py +118 -0
  75. backtrader/brokers/mixbroker.py +895 -0
  76. backtrader/brokers/tickbroker.py +1991 -0
  77. backtrader/btrun/__init__.py +12 -0
  78. backtrader/btrun/btrun.py +1218 -0
  79. backtrader/cerebro.py +828 -0
  80. backtrader/channel.py +682 -0
  81. backtrader/channels/__init__.py +23 -0
  82. backtrader/channels/bridge.py +186 -0
  83. backtrader/channels/funding.py +248 -0
  84. backtrader/channels/live_queue.py +216 -0
  85. backtrader/channels/live_validator.py +294 -0
  86. backtrader/channels/orderbook.py +257 -0
  87. backtrader/channels/tick.py +202 -0
  88. backtrader/comminfo.py +665 -0
  89. backtrader/commissions/__init__.py +106 -0
  90. backtrader/commissions/ctpoption.py +993 -0
  91. backtrader/configs/account_config_example.yaml +8 -0
  92. backtrader/dataseries.py +379 -0
  93. backtrader/errors.py +106 -0
  94. backtrader/events.py +980 -0
  95. backtrader/feed.py +1523 -0
  96. backtrader/feeds/__init__.py +75 -0
  97. backtrader/feeds/barrier.py +2006 -0
  98. backtrader/feeds/blaze.py +118 -0
  99. backtrader/feeds/btapifeed.py +1538 -0
  100. backtrader/feeds/btcsv.py +203 -0
  101. backtrader/feeds/chainer.py +114 -0
  102. backtrader/feeds/cryptohftdata.py +164 -0
  103. backtrader/feeds/csvgeneric.py +1205 -0
  104. backtrader/feeds/ctpcohort.py +1051 -0
  105. backtrader/feeds/influxfeed.py +158 -0
  106. backtrader/feeds/livefeed.py +71 -0
  107. backtrader/feeds/mixed_channel.py +108 -0
  108. backtrader/feeds/mt4csv.py +42 -0
  109. backtrader/feeds/pandafeed.py +381 -0
  110. backtrader/feeds/quandl.py +256 -0
  111. backtrader/feeds/rollover.py +229 -0
  112. backtrader/feeds/sierrachart.py +30 -0
  113. backtrader/feeds/vchart.py +162 -0
  114. backtrader/feeds/vchartcsv.py +84 -0
  115. backtrader/feeds/vchartfile.py +153 -0
  116. backtrader/feeds/yahoo.py +399 -0
  117. backtrader/fillers.py +148 -0
  118. backtrader/filters/__init__.py +34 -0
  119. backtrader/filters/bsplitter.py +127 -0
  120. backtrader/filters/calendardays.py +121 -0
  121. backtrader/filters/datafiller.py +192 -0
  122. backtrader/filters/datafilter.py +74 -0
  123. backtrader/filters/daysteps.py +96 -0
  124. backtrader/filters/heikinashi.py +63 -0
  125. backtrader/filters/renko.py +164 -0
  126. backtrader/filters/session.py +289 -0
  127. backtrader/flt.py +80 -0
  128. backtrader/functions.py +960 -0
  129. backtrader/indicator.py +449 -0
  130. backtrader/indicators/__init__.py +148 -0
  131. backtrader/indicators/accdecoscillator.py +110 -0
  132. backtrader/indicators/aroon.py +300 -0
  133. backtrader/indicators/atr.py +315 -0
  134. backtrader/indicators/awesomeoscillator.py +122 -0
  135. backtrader/indicators/basicops.py +834 -0
  136. backtrader/indicators/bollinger.py +223 -0
  137. backtrader/indicators/cci.py +89 -0
  138. backtrader/indicators/channels_ext.py +83 -0
  139. backtrader/indicators/contrib/__init__.py +228 -0
  140. backtrader/indicators/contrib/absolutely_no_lag_lwma.py +28 -0
  141. backtrader/indicators/contrib/absolutely_no_lag_lwma_color.py +44 -0
  142. backtrader/indicators/contrib/accumulation_distribution_line.py +92 -0
  143. backtrader/indicators/contrib/adx_cross_hull_style_indicator.py +249 -0
  144. backtrader/indicators/contrib/adxdmi.py +34 -0
  145. backtrader/indicators/contrib/ai_acceleration_deceleration_oscillator.py +34 -0
  146. backtrader/indicators/contrib/altr_trend_signal_v22.py +85 -0
  147. backtrader/indicators/contrib/anchored_momentum_line.py +115 -0
  148. backtrader/indicators/contrib/any_range_cld_tail_indicator.py +82 -0
  149. backtrader/indicators/contrib/aroon_horn_sign_indicator.py +96 -0
  150. backtrader/indicators/contrib/aroon_oscillator_sign_alert.py +50 -0
  151. backtrader/indicators/contrib/arrows_curves_indicator.py +112 -0
  152. backtrader/indicators/contrib/as_ctrend_indicator.py +143 -0
  153. backtrader/indicators/contrib/asimmetric_stoch_nr_indicator.py +187 -0
  154. backtrader/indicators/contrib/atr_normalize_histogram.py +118 -0
  155. backtrader/indicators/contrib/average_change_candle.py +165 -0
  156. backtrader/indicators/contrib/bb_squeeze_indicator.py +60 -0
  157. backtrader/indicators/contrib/bezier_st_dev_indicator.py +135 -0
  158. backtrader/indicators/contrib/binary_wave_indicator.py +233 -0
  159. backtrader/indicators/contrib/blau_c_momentum_indicator.py +123 -0
  160. backtrader/indicators/contrib/blau_cmi_indicator.py +141 -0
  161. backtrader/indicators/contrib/blau_csi.py +76 -0
  162. backtrader/indicators/contrib/blau_ergodic.py +53 -0
  163. backtrader/indicators/contrib/blau_t_stoch_i.py +72 -0
  164. backtrader/indicators/contrib/blau_ts_stochastic.py +85 -0
  165. backtrader/indicators/contrib/blau_tvi.py +55 -0
  166. backtrader/indicators/contrib/brain_trend2_indicator.py +128 -0
  167. backtrader/indicators/contrib/brain_trend_signal_proxy.py +47 -0
  168. backtrader/indicators/contrib/brake_parb_indicator.py +85 -0
  169. backtrader/indicators/contrib/breakout_bars_trend_v2.py +121 -0
  170. backtrader/indicators/contrib/bsi_indicator.py +87 -0
  171. backtrader/indicators/contrib/bulls_bears_eyes.py +67 -0
  172. backtrader/indicators/contrib/bulls_power.py +56 -0
  173. backtrader/indicators/contrib/bw_wise_man1_signal.py +102 -0
  174. backtrader/indicators/contrib/bykov_trend_indicator.py +85 -0
  175. backtrader/indicators/contrib/candle_stop_color.py +46 -0
  176. backtrader/indicators/contrib/candles_x_smoothed_indicator.py +69 -0
  177. backtrader/indicators/contrib/candlesticks_bw.py +45 -0
  178. backtrader/indicators/contrib/caudate_x_period_candle_color.py +56 -0
  179. backtrader/indicators/contrib/cci_histogram_indicator.py +53 -0
  180. backtrader/indicators/contrib/cci_woodies_indicator.py +80 -0
  181. backtrader/indicators/contrib/center_of_gravity_candle_indicator.py +83 -0
  182. backtrader/indicators/contrib/center_of_gravity_indicator.py +70 -0
  183. backtrader/indicators/contrib/cg_oscillator.py +40 -0
  184. backtrader/indicators/contrib/close_line_cci.py +38 -0
  185. backtrader/indicators/contrib/close_price_fractals.py +47 -0
  186. backtrader/indicators/contrib/color3rd_gen_xma_indicator.py +122 -0
  187. backtrader/indicators/contrib/color_bb_candles_indicator.py +108 -0
  188. backtrader/indicators/contrib/color_coppock_indicator.py +157 -0
  189. backtrader/indicators/contrib/color_hma.py +71 -0
  190. backtrader/indicators/contrib/color_j_variation_indicator.py +53 -0
  191. backtrader/indicators/contrib/color_metro_de_marker_indicator.py +78 -0
  192. backtrader/indicators/contrib/color_metro_stochastic_indicator.py +93 -0
  193. backtrader/indicators/contrib/color_metro_wpr_indicator.py +85 -0
  194. backtrader/indicators/contrib/color_schaff_de_marker_trend_cycle.py +92 -0
  195. backtrader/indicators/contrib/color_schaff_trend_cycle_indicator.py +203 -0
  196. backtrader/indicators/contrib/color_step_xccx_indicator.py +193 -0
  197. backtrader/indicators/contrib/color_x2_ma.py +49 -0
  198. backtrader/indicators/contrib/color_x_derivative.py +63 -0
  199. backtrader/indicators/contrib/color_zerolag_de_marker.py +84 -0
  200. backtrader/indicators/contrib/corrected_average_indicator.py +127 -0
  201. backtrader/indicators/contrib/darvas_boxes_system.py +73 -0
  202. backtrader/indicators/contrib/dema_range_channel_color.py +42 -0
  203. backtrader/indicators/contrib/derivative_indicator.py +95 -0
  204. backtrader/indicators/contrib/digital_ft01_indicator.py +112 -0
  205. backtrader/indicators/contrib/digital_macd.py +200 -0
  206. backtrader/indicators/contrib/donchian_channels_system.py +45 -0
  207. backtrader/indicators/contrib/dots_indicator.py +93 -0
  208. backtrader/indicators/contrib/ef_distance_indicator.py +82 -0
  209. backtrader/indicators/contrib/ema_rsi_va.py +80 -0
  210. backtrader/indicators/contrib/envelopes_jp_alonso.py +32 -0
  211. backtrader/indicators/contrib/f2a_ao_indicator.py +120 -0
  212. backtrader/indicators/contrib/fatl_filter.py +179 -0
  213. backtrader/indicators/contrib/fibo_candles_indicator.py +78 -0
  214. backtrader/indicators/contrib/fine_tuning_ma.py +100 -0
  215. backtrader/indicators/contrib/fisher_org_v1.py +102 -0
  216. backtrader/indicators/contrib/fisher_org_v1_sign.py +118 -0
  217. backtrader/indicators/contrib/force_index_ema.py +96 -0
  218. backtrader/indicators/contrib/force_index_ema_2.py +27 -0
  219. backtrader/indicators/contrib/forecast_oscilator.py +145 -0
  220. backtrader/indicators/contrib/fractal_amambk.py +81 -0
  221. backtrader/indicators/contrib/frama_series.py +84 -0
  222. backtrader/indicators/contrib/frasm_av2_indicator.py +104 -0
  223. backtrader/indicators/contrib/go_indicator.py +93 -0
  224. backtrader/indicators/contrib/hlr_indicator.py +95 -0
  225. backtrader/indicators/contrib/hma.py +50 -0
  226. backtrader/indicators/contrib/i4_drfv2.py +34 -0
  227. backtrader/indicators/contrib/i4_drfv3.py +38 -0
  228. backtrader/indicators/contrib/i_anch_mom_indicator.py +72 -0
  229. backtrader/indicators/contrib/i_de_marker_sign_indicator.py +64 -0
  230. backtrader/indicators/contrib/i_gap_indicator.py +45 -0
  231. backtrader/indicators/contrib/i_stoch_komposter_indicator.py +77 -0
  232. backtrader/indicators/contrib/i_trend_indicator.py +125 -0
  233. backtrader/indicators/contrib/iamma_indicator.py +39 -0
  234. backtrader/indicators/contrib/indexed_moving_average.py +33 -0
  235. backtrader/indicators/contrib/instantaneous_trend_filter_indicator.py +51 -0
  236. backtrader/indicators/contrib/inverse_reaction_indicator.py +41 -0
  237. backtrader/indicators/contrib/irsi_sign_indicator.py +95 -0
  238. backtrader/indicators/contrib/iwpr_sign_indicator.py +59 -0
  239. backtrader/indicators/contrib/j_brain_trend1_sig_indicator.py +233 -0
  240. backtrader/indicators/contrib/j_tpo_proxy.py +32 -0
  241. backtrader/indicators/contrib/jma_slope_indicator.py +73 -0
  242. backtrader/indicators/contrib/kalman_filter_indicator.py +119 -0
  243. backtrader/indicators/contrib/kalman_filter_line.py +127 -0
  244. backtrader/indicators/contrib/kama_indicator.py +150 -0
  245. backtrader/indicators/contrib/karacatica_indicator.py +99 -0
  246. backtrader/indicators/contrib/kdj_indicator.py +59 -0
  247. backtrader/indicators/contrib/kwan_ccc_indicator.py +195 -0
  248. backtrader/indicators/contrib/kwan_nrp_indicator.py +113 -0
  249. backtrader/indicators/contrib/kwan_rdp_indicator.py +192 -0
  250. backtrader/indicators/contrib/laguerre_adx_indicator.py +85 -0
  251. backtrader/indicators/contrib/laguerre_filter_indicator.py +66 -0
  252. backtrader/indicators/contrib/laguerre_plus_di_proxy.py +57 -0
  253. backtrader/indicators/contrib/laguerre_roc_indicator.py +81 -0
  254. backtrader/indicators/contrib/le_man_signal_indicator.py +63 -0
  255. backtrader/indicators/contrib/linear_reg_slope_v2_indicator.py +136 -0
  256. backtrader/indicators/contrib/loco_indicator.py +88 -0
  257. backtrader/indicators/contrib/lrma_indicator.py +185 -0
  258. backtrader/indicators/contrib/lsma_angle_indicator.py +106 -0
  259. backtrader/indicators/contrib/ma_rounding_channel_indicator.py +149 -0
  260. backtrader/indicators/contrib/macd2_indicator.py +61 -0
  261. backtrader/indicators/contrib/macd_candle_indicator.py +80 -0
  262. backtrader/indicators/contrib/malr_indicator.py +77 -0
  263. backtrader/indicators/contrib/momentum_candle_sign_indicator.py +51 -0
  264. backtrader/indicators/contrib/moving_average_fn_indicator.py +139 -0
  265. backtrader/indicators/contrib/mt5_stochastic_close_close.py +57 -0
  266. backtrader/indicators/contrib/muv_nor_diff_cloud_indicator.py +107 -0
  267. backtrader/indicators/contrib/non_lag_dot_indicator.py +124 -0
  268. backtrader/indicators/contrib/nrtr_extr_indicator.py +95 -0
  269. backtrader/indicators/contrib/nrtr_indicator.py +95 -0
  270. backtrader/indicators/contrib/p_channel_system.py +40 -0
  271. backtrader/indicators/contrib/percent_envelope.py +37 -0
  272. backtrader/indicators/contrib/percentage_crossover_channel.py +47 -0
  273. backtrader/indicators/contrib/pivot_zig_zag_proxy.py +47 -0
  274. backtrader/indicators/contrib/price_channel_stop_indicator.py +104 -0
  275. backtrader/indicators/contrib/price_extreme_channel.py +35 -0
  276. backtrader/indicators/contrib/qqe_cloud_indicator.py +129 -0
  277. backtrader/indicators/contrib/ravi_indicator.py +40 -0
  278. backtrader/indicators/contrib/raw_close_close_stochastic.py +74 -0
  279. backtrader/indicators/contrib/rd_trend_trigger_indicator.py +51 -0
  280. backtrader/indicators/contrib/renko_level.py +85 -0
  281. backtrader/indicators/contrib/renko_line_break.py +91 -0
  282. backtrader/indicators/contrib/rftl_indicator.py +41 -0
  283. backtrader/indicators/contrib/rkd_indicator.py +53 -0
  284. backtrader/indicators/contrib/roc2_vg_indicator.py +68 -0
  285. backtrader/indicators/contrib/rsi_histogram_indicator.py +43 -0
  286. backtrader/indicators/contrib/rsi_slowdown.py +57 -0
  287. backtrader/indicators/contrib/rsioma_v2.py +41 -0
  288. backtrader/indicators/contrib/rvi_histogram_indicator.py +107 -0
  289. backtrader/indicators/contrib/safe_adx.py +89 -0
  290. backtrader/indicators/contrib/shared_strategy_indicators.py +1651 -0
  291. backtrader/indicators/contrib/sidus_indicator.py +105 -0
  292. backtrader/indicators/contrib/silver_trend_indicator.py +79 -0
  293. backtrader/indicators/contrib/sliding_range_color.py +56 -0
  294. backtrader/indicators/contrib/slow_stoch.py +42 -0
  295. backtrader/indicators/contrib/smoothed_adx_indicator.py +86 -0
  296. backtrader/indicators/contrib/smoothed_rsi.py +31 -0
  297. backtrader/indicators/contrib/spearman_rank_correlation_histogram.py +60 -0
  298. backtrader/indicators/contrib/stalin_indicator.py +152 -0
  299. backtrader/indicators/contrib/starter_laguerre_filter.py +62 -0
  300. backtrader/indicators/contrib/step_manrtr_indicator.py +137 -0
  301. backtrader/indicators/contrib/stochastic_histogram_indicator.py +143 -0
  302. backtrader/indicators/contrib/t3_alarm_indicator.py +125 -0
  303. backtrader/indicators/contrib/t3_average.py +76 -0
  304. backtrader/indicators/contrib/t3_indicator.py +40 -0
  305. backtrader/indicators/contrib/the20s_v020_signal.py +93 -0
  306. backtrader/indicators/contrib/three_candles_indicator.py +70 -0
  307. backtrader/indicators/contrib/three_line_break_indicator.py +64 -0
  308. backtrader/indicators/contrib/time_line.py +57 -0
  309. backtrader/indicators/contrib/trading_channel_index_proxy.py +48 -0
  310. backtrader/indicators/contrib/trend_arrows_indicator.py +109 -0
  311. backtrader/indicators/contrib/trend_continuation_indicator.py +127 -0
  312. backtrader/indicators/contrib/trend_intensity_index_proxy.py +51 -0
  313. backtrader/indicators/contrib/trend_manager_indicator.py +39 -0
  314. backtrader/indicators/contrib/tri_x_candle_indicator.py +51 -0
  315. backtrader/indicators/contrib/trigger_line.py +66 -0
  316. backtrader/indicators/contrib/triple_ema_rate.py +34 -0
  317. backtrader/indicators/contrib/trvi_indicator.py +194 -0
  318. backtrader/indicators/contrib/two_pb_ideal_xosma_indicator.py +127 -0
  319. backtrader/indicators/contrib/ultra_absolutely_no_lag_lwma_color.py +92 -0
  320. backtrader/indicators/contrib/ultra_wpr_indicator.py +173 -0
  321. backtrader/indicators/contrib/up_down_candle_strength.py +68 -0
  322. backtrader/indicators/contrib/vinin_i_trend_indicator.py +139 -0
  323. backtrader/indicators/contrib/volume_weighted_ma_indicator.py +78 -0
  324. backtrader/indicators/contrib/volume_weighted_ma_st_dev_indicator.py +111 -0
  325. backtrader/indicators/contrib/vwap_close_indicator.py +65 -0
  326. backtrader/indicators/contrib/vwma_candle.py +57 -0
  327. backtrader/indicators/contrib/vwma_digit_system.py +70 -0
  328. backtrader/indicators/contrib/wami.py +43 -0
  329. backtrader/indicators/contrib/wprsi_signal_indicator.py +105 -0
  330. backtrader/indicators/contrib/x_de_marker_histogram_vol_direct_indicator.py +145 -0
  331. backtrader/indicators/contrib/x_fisher_indicator.py +64 -0
  332. backtrader/indicators/contrib/xcci_histogram_vol_direct_indicator.py +56 -0
  333. backtrader/indicators/contrib/xcci_histogram_vol_indicator.py +85 -0
  334. backtrader/indicators/contrib/xma_ichimoku.py +163 -0
  335. backtrader/indicators/contrib/xma_ishimoku_channel_indicator.py +65 -0
  336. backtrader/indicators/contrib/xma_ishimoku_line.py +68 -0
  337. backtrader/indicators/contrib/xma_range_bands_indicator.py +107 -0
  338. backtrader/indicators/contrib/xmacd_indicator.py +70 -0
  339. backtrader/indicators/contrib/xrsi_de_marker_histogram.py +67 -0
  340. backtrader/indicators/contrib/xrsi_histogram_vol_direct_indicator.py +52 -0
  341. backtrader/indicators/contrib/xrsi_histogram_vol_indicator.py +81 -0
  342. backtrader/indicators/contrib/xrvi_indicator.py +130 -0
  343. backtrader/indicators/contrib/zero_lag_macd.py +36 -0
  344. backtrader/indicators/contrib/zig_zag_recent_pivot_signal.py +90 -0
  345. backtrader/indicators/contrib/zpf_indicator.py +115 -0
  346. backtrader/indicators/crossover.py +337 -0
  347. backtrader/indicators/dema.py +175 -0
  348. backtrader/indicators/demarker.py +270 -0
  349. backtrader/indicators/deviation.py +284 -0
  350. backtrader/indicators/directionalmove.py +1071 -0
  351. backtrader/indicators/dma.py +112 -0
  352. backtrader/indicators/dpo.py +96 -0
  353. backtrader/indicators/dv2.py +56 -0
  354. backtrader/indicators/ema.py +145 -0
  355. backtrader/indicators/envelope.py +475 -0
  356. backtrader/indicators/hadelta.py +198 -0
  357. backtrader/indicators/heikinashi.py +153 -0
  358. backtrader/indicators/hma.py +153 -0
  359. backtrader/indicators/hurst.py +151 -0
  360. backtrader/indicators/ichimoku.py +267 -0
  361. backtrader/indicators/kama.py +181 -0
  362. backtrader/indicators/kst.py +159 -0
  363. backtrader/indicators/lrsi.py +125 -0
  364. backtrader/indicators/mabase.py +147 -0
  365. backtrader/indicators/macd.py +322 -0
  366. backtrader/indicators/momentum.py +267 -0
  367. backtrader/indicators/moneyflow.py +237 -0
  368. backtrader/indicators/mt5atr.py +124 -0
  369. backtrader/indicators/myind.py +179 -0
  370. backtrader/indicators/obv.py +94 -0
  371. backtrader/indicators/ols.py +265 -0
  372. backtrader/indicators/oscillator.py +161 -0
  373. backtrader/indicators/percentchange.py +83 -0
  374. backtrader/indicators/percentrank.py +46 -0
  375. backtrader/indicators/pivotpoint.py +469 -0
  376. backtrader/indicators/prettygoodoscillator.py +113 -0
  377. backtrader/indicators/priceops_ext.py +123 -0
  378. backtrader/indicators/priceoscillator.py +262 -0
  379. backtrader/indicators/psar.py +212 -0
  380. backtrader/indicators/rmi.py +69 -0
  381. backtrader/indicators/rsi.py +440 -0
  382. backtrader/indicators/sma.py +141 -0
  383. backtrader/indicators/smma.py +116 -0
  384. backtrader/indicators/spread.py +54 -0
  385. backtrader/indicators/stochastic.py +263 -0
  386. backtrader/indicators/supertrend.py +436 -0
  387. backtrader/indicators/trend_ext.py +105 -0
  388. backtrader/indicators/trix.py +202 -0
  389. backtrader/indicators/tsi.py +155 -0
  390. backtrader/indicators/ultimateoscillator.py +158 -0
  391. backtrader/indicators/vortex.py +62 -0
  392. backtrader/indicators/williams.py +194 -0
  393. backtrader/indicators/wma.py +103 -0
  394. backtrader/indicators/zlema.py +135 -0
  395. backtrader/indicators/zlind.py +104 -0
  396. backtrader/linebuffer.py +3155 -0
  397. backtrader/lineiterator.py +2911 -0
  398. backtrader/lineroot.py +1106 -0
  399. backtrader/lineseries.py +2559 -0
  400. backtrader/live_trading/__init__.py +31 -0
  401. backtrader/live_trading/interface.py +404 -0
  402. backtrader/mathsupport.py +94 -0
  403. backtrader/metabase.py +1804 -0
  404. backtrader/mixins/__init__.py +21 -0
  405. backtrader/mixins/singleton.py +118 -0
  406. backtrader/observer.py +106 -0
  407. backtrader/observers/__init__.py +45 -0
  408. backtrader/observers/benchmark.py +126 -0
  409. backtrader/observers/broker.py +184 -0
  410. backtrader/observers/buysell.py +144 -0
  411. backtrader/observers/drawdown.py +161 -0
  412. backtrader/observers/logreturns.py +113 -0
  413. backtrader/observers/timereturn.py +86 -0
  414. backtrader/observers/trade_logger.py +2972 -0
  415. backtrader/observers/tradelogger.py +6 -0
  416. backtrader/observers/trades.py +258 -0
  417. backtrader/order.py +1114 -0
  418. backtrader/parameters.py +2345 -0
  419. backtrader/plot/__init__.py +54 -0
  420. backtrader/plot/finance.py +1022 -0
  421. backtrader/plot/formatters.py +200 -0
  422. backtrader/plot/locator.py +353 -0
  423. backtrader/plot/multicursor.py +495 -0
  424. backtrader/plot/plot.py +2500 -0
  425. backtrader/plot/plot_plotly.py +1351 -0
  426. backtrader/plot/scheme.py +253 -0
  427. backtrader/plot/utils.py +104 -0
  428. backtrader/position.py +290 -0
  429. backtrader/position_modes.py +132 -0
  430. backtrader/profiles.py +254 -0
  431. backtrader/reports/__init__.py +39 -0
  432. backtrader/reports/charts.py +371 -0
  433. backtrader/reports/performance.py +620 -0
  434. backtrader/reports/reporter.py +660 -0
  435. backtrader/resamplerfilter.py +1001 -0
  436. backtrader/signal.py +118 -0
  437. backtrader/signals/__init__.py +17 -0
  438. backtrader/sizer.py +114 -0
  439. backtrader/sizers/__init__.py +26 -0
  440. backtrader/sizers/fixedsize.py +161 -0
  441. backtrader/sizers/percents_sizer.py +119 -0
  442. backtrader/store.py +221 -0
  443. backtrader/stores/__init__.py +33 -0
  444. backtrader/stores/btapistore.py +15506 -0
  445. backtrader/stores/livestore.py +137 -0
  446. backtrader/stores/vchartfile.py +96 -0
  447. backtrader/strategy.py +3655 -0
  448. backtrader/talib.py +280 -0
  449. backtrader/test_helpers.py +96 -0
  450. backtrader/timer.py +358 -0
  451. backtrader/trade.py +442 -0
  452. backtrader/tradingcal.py +361 -0
  453. backtrader/utils/__init__.py +68 -0
  454. backtrader/utils/autodict.py +251 -0
  455. backtrader/utils/date.py +71 -0
  456. backtrader/utils/dateintern.py +509 -0
  457. backtrader/utils/flushfile.py +94 -0
  458. backtrader/utils/fractal.py +101 -0
  459. backtrader/utils/get_metrics.py +101 -0
  460. backtrader/utils/load_data.py +209 -0
  461. backtrader/utils/log_message.py +998 -0
  462. backtrader/utils/ordereddefaultdict.py +75 -0
  463. backtrader/utils/py3.py +296 -0
  464. backtrader/version.py +21 -0
  465. 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