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,115 @@
1
+ #!/usr/bin/env python
2
+ """Functional-test indicators migrated to contrib.
3
+
4
+ Generated from a single functional strategy module to preserve file-local
5
+ helper functions and constants without cross-test name collisions.
6
+ """
7
+
8
+ from .. import (
9
+ EMA,
10
+ SMA,
11
+ Indicator,
12
+ SmoothedMovingAverage,
13
+ WeightedMovingAverage,
14
+ )
15
+
16
+ __all__ = [
17
+ "ZPFIndicator",
18
+ ]
19
+
20
+
21
+ def resolve_ma_class(name):
22
+ """Map a moving-average name to its backtrader indicator class.
23
+
24
+ Args:
25
+ name: MA type name (e.g. ``sma``, ``ema``, ``smma`` or MT5-style
26
+ ``mode_*`` variants).
27
+
28
+ Returns:
29
+ The matching backtrader moving-average indicator class, defaulting to
30
+ the weighted moving average for unrecognized names.
31
+ """
32
+ mode = str(name).lower()
33
+ if mode in {"sma", "mode_sma"}:
34
+ return SMA
35
+ if mode in {"ema", "mode_ema"}:
36
+ return EMA
37
+ if mode in {"smma", "mode_smma"}:
38
+ return SmoothedMovingAverage
39
+ return WeightedMovingAverage
40
+
41
+
42
+ def resolve_price_line(data, mode):
43
+ """Return the applied-price line for a data feed given a price mode.
44
+
45
+ Args:
46
+ data: The data feed providing OHLC lines.
47
+ mode: Applied-price selector (e.g. ``price_close``, ``price_median``,
48
+ ``price_typical`` or their short forms).
49
+
50
+ Returns:
51
+ A line expression for the selected applied price, defaulting to the
52
+ close for unrecognized modes.
53
+ """
54
+ price_mode = str(mode).lower()
55
+ if price_mode in {"price_open", "open"}:
56
+ return data.open
57
+ if price_mode in {"price_high", "high"}:
58
+ return data.high
59
+ if price_mode in {"price_low", "low"}:
60
+ return data.low
61
+ if price_mode in {"price_median", "median"}:
62
+ return (data.high + data.low) / 2.0
63
+ if price_mode in {"price_typical", "typical"}:
64
+ return (data.high + data.low + data.close) / 3.0
65
+ if price_mode in {"price_weighted", "weighted"}:
66
+ return (data.high + data.low + data.close + data.close) / 4.0
67
+ if price_mode in {"price_simpl", "simpl"}:
68
+ return (data.open + data.close) / 2.0
69
+ if price_mode in {"price_quarter", "quarter"}:
70
+ return (data.high + data.low + data.open + data.close) / 4.0
71
+ if price_mode in {"price_trendfollow0", "trendfollow0"}:
72
+ return (data.high + data.low + data.close + data.close) / 4.0
73
+ if price_mode in {"price_trendfollow1", "trendfollow1"}:
74
+ return (data.high + data.low + data.close + data.open + data.close) / 5.0
75
+ return data.close
76
+
77
+
78
+ class ZPFIndicator(Indicator):
79
+ """Zero Power Flow oscillator (volume-weighted MA spread).
80
+
81
+ Multiplies a moving average of volume by the gap between a short and a long
82
+ moving average of an applied price, producing a volume-weighted
83
+ trend-strength value (``zpf``) that oscillates around zero, with symmetric
84
+ ``line1``/``line2`` envelopes.
85
+ """
86
+
87
+ lines = (
88
+ "line1",
89
+ "line2",
90
+ "zpf",
91
+ )
92
+ params = (
93
+ ("xma_method", "sma"),
94
+ ("xlength", 12),
95
+ ("xphase", 15),
96
+ ("ipc", "price_close"),
97
+ ("volume_type", "tick"),
98
+ )
99
+
100
+ def __init__(self):
101
+ """Build the price/volume moving averages and the ZPF lines."""
102
+ ma_cls = resolve_ma_class(self.p.xma_method)
103
+ price_line = resolve_price_line(self.data, self.p.ipc)
104
+ volume_line = (
105
+ self.data.volume
106
+ if str(self.p.volume_type).lower() == "tick"
107
+ else self.data.openinterest
108
+ )
109
+ self.x1ma = ma_cls(price_line, period=self.p.xlength)
110
+ self.x2ma = ma_cls(price_line, period=max(1, 2 * self.p.xlength))
111
+ self.xvol = ma_cls(volume_line, period=self.p.xlength)
112
+ self.lines.zpf = self.xvol * (self.x1ma - self.x2ma) / 2.0
113
+ self.lines.line1 = -self.lines.zpf
114
+ self.lines.line2 = self.lines.zpf
115
+ self.addminperiod(max(2 * self.p.xlength, self.p.xlength) + 2)
@@ -0,0 +1,337 @@
1
+ #!/usr/bin/env python
2
+ """Crossover Indicator Module - Crossover detection indicators.
3
+
4
+ This module provides indicators for detecting when two data series cross
5
+ each other (upward or downward).
6
+
7
+ Classes:
8
+ NonZeroDifference: Tracks difference, memorizing last non-zero value (alias: NZD).
9
+ CrossUp: Detects upward crossover.
10
+ CrossDown: Detects downward crossover.
11
+ CrossOver: Detects both directional crossovers.
12
+
13
+ Example:
14
+ class MyStrategy(bt.Strategy):
15
+ def __init__(self):
16
+ self.sma_fast = bt.indicators.SMA(self.data, period=10)
17
+ self.sma_slow = bt.indicators.SMA(self.data, period=20)
18
+ self.crossover = bt.indicators.CrossOver(self.sma_fast, self.sma_slow)
19
+
20
+ def next(self):
21
+ if self.crossover[0] > 0:
22
+ self.buy()
23
+ elif self.crossover[0] < 0:
24
+ self.sell()
25
+ """
26
+
27
+ from . import Indicator
28
+
29
+
30
+ class NonZeroDifference(Indicator):
31
+ """
32
+ Keeps track of the difference between two data inputs, memorizing
33
+ the last non-zero value if the current difference is zero
34
+ """
35
+
36
+ _mindatas = 2
37
+ alias = ("NZD",)
38
+ lines = ("nzd",)
39
+
40
+ def __init__(self):
41
+ """Initialize the NonZeroDifference indicator.
42
+
43
+ Tracks difference between two data sources.
44
+ """
45
+ super().__init__()
46
+
47
+ def nextstart(self):
48
+ """Initialize NZD on first valid bar.
49
+
50
+ Sets initial difference value.
51
+ """
52
+ self.l.nzd[0] = self.data0[0] - self.data1[0]
53
+
54
+ def next(self):
55
+ """Calculate NZD for the current bar.
56
+
57
+ Memorizes last non-zero difference when current difference is zero.
58
+ """
59
+ d = self.data0[0] - self.data1[0]
60
+ # Memorize last non-zero value
61
+ new_val = d if d else self.l.nzd[-1]
62
+ self.l.nzd[0] = new_val
63
+
64
+ # Don't override once() - let framework call next() for each bar
65
+
66
+
67
+ class _CrossBase(Indicator):
68
+ _mindatas = 2
69
+ lines = ("cross",)
70
+ plotinfo = {"plotymargin": 0.05, "plotyhlines": [0.0, 1.0]}
71
+
72
+ def __init__(self):
73
+ """Initialize the crossover base indicator.
74
+
75
+ Creates NonZeroDifference for crossover detection.
76
+ """
77
+ super().__init__() # CRITICAL: Call parent init first
78
+ self.nzd = NonZeroDifference(self.data0, self.data1)
79
+
80
+ def next(self):
81
+ """Detect crossover for the current bar.
82
+
83
+ Returns 1.0 if crossover detected, 0.0 otherwise.
84
+ """
85
+ # Check for crossover
86
+ if hasattr(self, "_crossup"):
87
+ if self._crossup:
88
+ # Upward cross: previous diff < 0 (strictly), now data0 > data1
89
+ before = self.nzd(-1) < 0.0 # STRICT inequality
90
+ after = self.data0[0] > self.data1[0]
91
+ else:
92
+ # Downward cross: previous diff > 0 (strictly), now data0 < data1
93
+ before = self.nzd(-1) > 0.0 # STRICT inequality
94
+ after = self.data0[0] < self.data1[0]
95
+
96
+ self.lines.cross[0] = 1.0 if (before and after) else 0.0
97
+ else:
98
+ self.lines.cross[0] = 0.0
99
+
100
+ # Don't override once() - let framework call next() for each bar
101
+
102
+
103
+ class CrossUp(_CrossBase):
104
+ """Upward cross indicator"""
105
+
106
+ _crossup = True
107
+
108
+
109
+ class CrossDown(_CrossBase):
110
+ """Downward cross indicator"""
111
+
112
+ _crossup = False
113
+
114
+
115
+ class CrossOver(Indicator):
116
+ """
117
+ Gives signal for data crossover:
118
+ 1.0 for upward cross, -1.0 for downward cross, 0.0 otherwise
119
+ """
120
+
121
+ _mindatas = 2
122
+ lines = ("crossover",)
123
+ plotinfo = {"plotymargin": 0.05, "plotyhlines": [-1.0, 1.0]}
124
+
125
+ def __init__(self):
126
+ """Initialize the CrossOver indicator.
127
+
128
+ Sets up minperiod and tracking variables for crossover detection.
129
+ """
130
+ super().__init__()
131
+ # CRITICAL FIX: Inherit minperiod from data sources first
132
+ # This is needed because the framework's automatic inheritance isn't working
133
+ if hasattr(self, "datas") and self.datas:
134
+ data_minperiods = [getattr(d, "_minperiod", 1) for d in self.datas]
135
+ self._minperiod = max([self._minperiod] + data_minperiods)
136
+ # CRITICAL FIX: Add minperiod for lookback requirement (nzd(-1) in master)
137
+ # addminperiod(n) adds n-1 to minperiod, so addminperiod(2) adds 1
138
+ self.addminperiod(2)
139
+ # For next() mode: track last non-zero difference
140
+ self._last_nzd = None
141
+ # CRITICAL FIX: Track owner's data length to detect replay mode
142
+ # In replay mode, we should only calculate crossover when the bar is complete
143
+ # The owner (strategy) has the actual data feed whose length changes when bars complete
144
+ self._last_owner_data_len = 0
145
+ self._owner_data = None # Will be set to owner's data feed in next()
146
+
147
+ def prenext(self):
148
+ """Track difference during warmup period.
149
+
150
+ Updates _last_nzd for use in nextstart/next crossover detection.
151
+ """
152
+ # Track difference during warmup period so _last_nzd is available in nextstart
153
+ # This is similar to MACD's prenext that calculates MACD values during warmup
154
+ diff = self.data0[0] - self.data1[0]
155
+ # Update _last_nzd (memorize non-zero)
156
+ if self._last_nzd is None:
157
+ self._last_nzd = diff
158
+ else:
159
+ self._last_nzd = diff if diff != 0.0 else self._last_nzd
160
+
161
+ def nextstart(self):
162
+ """Calculate crossover on first valid bar.
163
+
164
+ Handles replay mode special case and calculates initial crossover.
165
+ """
166
+ # CRITICAL FIX: In replay mode, the first bar after minperiod doesn't have a valid
167
+ # "previous" bar in the compressed timeframe context. Skip crossover calculation
168
+ # on the first bar ONLY when in replay mode. For normal mode, calculate normally.
169
+ diff = self.data0[0] - self.data1[0]
170
+
171
+ # Check if we're in replay mode by checking owner's datas for replaying attribute
172
+ is_replay = False
173
+ if hasattr(self, "_owner") and hasattr(self._owner, "datas"):
174
+ for data in self._owner.datas:
175
+ if hasattr(data, "replaying") and data.replaying > 0:
176
+ is_replay = True
177
+ break
178
+
179
+ if is_replay:
180
+ # In replay mode, skip crossover on first bar - set to 0 and update _last_nzd
181
+ self.lines.crossover[0] = 0.0
182
+ # Update _last_nzd for next()
183
+ prev_nzd = self._last_nzd if self._last_nzd is not None else diff
184
+ self._last_nzd = diff if diff != 0.0 else prev_nzd
185
+ return
186
+
187
+ # Normal mode: calculate crossover normally
188
+ # Get previous non-zero difference (set during prenext)
189
+ prev_nzd = self._last_nzd if self._last_nzd is not None else diff
190
+
191
+ # Check for crossover
192
+ up_cross = 1.0 if (prev_nzd < 0.0 and self.data0[0] > self.data1[0]) else 0.0
193
+ down_cross = 1.0 if (prev_nzd > 0.0 and self.data0[0] < self.data1[0]) else 0.0
194
+ self.lines.crossover[0] = up_cross - down_cross
195
+
196
+ # Update _last_nzd for next()
197
+ self._last_nzd = diff if diff != 0.0 else prev_nzd
198
+
199
+ def next(self):
200
+ """Calculate crossover for the current bar.
201
+
202
+ Returns 1.0 for upward cross, -1.0 for downward cross, 0.0 otherwise.
203
+ Handles replay mode correctly by deferring calculation when bars are updating.
204
+ """
205
+ # Current difference
206
+ diff = self.data0[0] - self.data1[0]
207
+
208
+ # CRITICAL FIX: In replay mode with runonce, the same bar is updated multiple times.
209
+ # The key insight is that we should only calculate crossover when we're at a NEW bar
210
+ # (idx has advanced), not when we're updating the same bar multiple times.
211
+ # We detect this by checking if idx < len - 1, which means we haven't advanced yet.
212
+ # IMPORTANT: Only apply this logic in replay mode, not in exactbars mode!
213
+
214
+ # Check if we're in replay mode
215
+ is_replay = False
216
+ if hasattr(self, "_owner") and hasattr(self._owner, "datas"):
217
+ for data in self._owner.datas:
218
+ if hasattr(data, "replaying") and data.replaying > 0:
219
+ is_replay = True
220
+ break
221
+
222
+ # Only defer crossover calculation in replay mode
223
+ if is_replay and hasattr(self.lines[0], "idx") and hasattr(self.lines[0], "__len__"):
224
+ current_idx = self.lines[0].idx
225
+ current_len = len(self.lines[0])
226
+ # If idx < len - 1, we're still filling the current bar, not at a new bar yet
227
+ # Defer crossover calculation by updating _last_nzd but setting crossover to 0
228
+ if current_idx < current_len - 1:
229
+ # Still updating current bar - defer crossover calculation
230
+ if self._last_nzd is None or diff != 0.0:
231
+ self._last_nzd = diff
232
+ self.lines.crossover[0] = 0.0
233
+ return
234
+
235
+ # At this point, we're at a new bar (idx == len - 1), calculate crossover
236
+ # using the previous bar's difference (stored in _last_nzd or from data[-1])
237
+ try:
238
+ prev_diff = self.data0[-1] - self.data1[-1]
239
+ # Find last non-zero difference by looking at line values
240
+ if prev_diff == 0.0:
241
+ prev_nzd = self._last_nzd if self._last_nzd is not None else diff
242
+ else:
243
+ prev_nzd = prev_diff
244
+ except (IndexError, TypeError):
245
+ # Fall back to cached value
246
+ prev_nzd = self._last_nzd if self._last_nzd is not None else diff
247
+
248
+ # Update _last_nzd for next bar
249
+ if self._last_nzd is None or diff != 0.0:
250
+ self._last_nzd = diff
251
+
252
+ # Check for crossover using STRICT inequalities
253
+ # Upward: prev < 0 and now data0 > data1
254
+ up_cross = 1.0 if (prev_nzd < 0.0 and self.data0[0] > self.data1[0]) else 0.0
255
+
256
+ # Downward: prev > 0 and now data0 < data1
257
+ down_cross = 1.0 if (prev_nzd > 0.0 and self.data0[0] < self.data1[0]) else 0.0
258
+
259
+ # Combine
260
+ self.lines.crossover[0] = up_cross - down_cross
261
+
262
+ def once(self, start, end):
263
+ """Calculate crossover in runonce mode.
264
+
265
+ Vectorized implementation that processes all bars at once.
266
+ """
267
+ # Vectorized once() implementation matching next() behavior
268
+ d0array = self.data0.array
269
+ d1array = self.data1.array
270
+ crossarray = self.line.array
271
+
272
+ # Handle case where data is shorter than minperiod
273
+ if start >= end:
274
+ # No bars to process - initialize all to 0
275
+ while len(crossarray) < len(d0array):
276
+ crossarray.append(0.0)
277
+ return
278
+
279
+ # Ensure array is large enough
280
+ while len(crossarray) < end:
281
+ crossarray.append(0.0)
282
+
283
+ # Defensive bound: never read past either input array. This protects
284
+ # against orphan sub-indicators (e.g., bt.indicators.SMA constructed
285
+ # at module level with no data) whose array remains empty when used
286
+ # as a CrossOver data source.
287
+ effective_end = min(end, len(d0array), len(d1array))
288
+ if effective_end <= start:
289
+ return
290
+
291
+ # Initialize prev_nzd from prenext period (bar before start)
292
+ # This matches next() which uses _last_nzd set during prenext
293
+ if start > 0 and start - 1 < len(d0array) and start - 1 < len(d1array):
294
+ prev_nzd = d0array[start - 1] - d1array[start - 1]
295
+ # Scan backwards to find last non-zero difference (like prenext does)
296
+ for j in range(start - 1, -1, -1):
297
+ diff_j = d0array[j] - d1array[j]
298
+ if diff_j != 0.0:
299
+ prev_nzd = diff_j
300
+ break
301
+ else:
302
+ prev_nzd = 0.0
303
+
304
+ # CRITICAL FIX: For replay mode, skip crossover on the very first bar.
305
+ # The first bar after minperiod doesn't have a valid "previous" bar in the
306
+ # compressed timeframe context. Defer crossover to the second bar.
307
+ # This prevents false positive crossovers at the start of replay data.
308
+ # ONLY apply this fix when in replay mode.
309
+ is_replay = False
310
+ if hasattr(self, "_owner") and hasattr(self._owner, "datas"):
311
+ for data in self._owner.datas:
312
+ if hasattr(data, "replaying") and data.replaying > 0:
313
+ is_replay = True
314
+ break
315
+
316
+ first_bar = start if is_replay else -1 # -1 means never skip
317
+
318
+ # Process ALL bars from start
319
+ for i in range(start, effective_end):
320
+ d0_val = d0array[i]
321
+ d1_val = d1array[i]
322
+ diff = d0_val - d1_val
323
+
324
+ # Skip crossover calculation on first bar ONLY in replay mode
325
+ if i == first_bar:
326
+ crossarray[i] = 0.0
327
+ # Still update prev_nzd for next iteration
328
+ prev_nzd = diff if diff != 0.0 else prev_nzd
329
+ continue
330
+
331
+ # Check crossover using prev_nzd (from previous bar)
332
+ up_cross = 1.0 if (prev_nzd < 0.0 and d0_val > d1_val) else 0.0
333
+ down_cross = 1.0 if (prev_nzd > 0.0 and d0_val < d1_val) else 0.0
334
+ crossarray[i] = up_cross - down_cross
335
+
336
+ # Update prev_nzd for next iteration (memorize non-zero)
337
+ prev_nzd = diff if diff != 0.0 else prev_nzd
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env python
2
+ """DEMA/TEMA Indicator Module - Double/Triple Exponential Moving Average.
3
+
4
+ This module provides DEMA and TEMA indicators introduced by Patrick G. Mulloy
5
+ in 1994 to reduce the lag associated with traditional moving averages.
6
+
7
+ Classes:
8
+ DoubleExponentialMovingAverage: DEMA indicator (alias: DEMA).
9
+ TripleExponentialMovingAverage: TEMA indicator (alias: TEMA).
10
+
11
+ Example:
12
+ class MyStrategy(bt.Strategy):
13
+ def __init__(self):
14
+ self.dema = bt.indicators.DEMA(self.data.close, period=20)
15
+
16
+ def next(self):
17
+ if self.data.close[0] > self.dema[0]:
18
+ self.buy()
19
+ elif self.data.close[0] < self.dema[0]:
20
+ self.sell()
21
+ """
22
+
23
+ import math
24
+
25
+ from . import MovingAverageBase
26
+ from .ema import EMA
27
+
28
+
29
+ class DoubleExponentialMovingAverage(MovingAverageBase):
30
+ """
31
+ DEMA was first time introduced in 1994, in the article "Smoothing Data with
32
+ Faster-Moving Averages" by Patrick G. Mulloy in "Technical Analysis of
33
+ Stocks & Commodities" magazine.
34
+
35
+ It attempts to reduce the inherent lag associated with Moving Averages
36
+
37
+ Formula:
38
+ - dema = (2.0 - ema(data, period) - ema(ema(data, period), period)
39
+
40
+ See:
41
+ (None)
42
+ """
43
+
44
+ alias = (
45
+ "DEMA",
46
+ "MovingAverageDoubleExponential",
47
+ )
48
+
49
+ lines = ("dema",)
50
+ params = (("_movav", EMA),)
51
+
52
+ def __init__(self):
53
+ """Initialize the DEMA indicator.
54
+
55
+ Creates two EMAs for the DEMA calculation.
56
+ """
57
+ super().__init__()
58
+ self.ema1 = self.p._movav(self.data, period=self.p.period)
59
+ self.ema2 = self.p._movav(self.ema1, period=self.p.period)
60
+ # minperiod = 2 * period - 1 for DEMA
61
+ self._minperiod = max(self._minperiod, 2 * self.p.period - 1)
62
+
63
+ def next(self):
64
+ """Calculate DEMA for the current bar.
65
+
66
+ Formula: DEMA = 2 * EMA1 - EMA(EMA1)
67
+ """
68
+ self.lines.dema[0] = 2.0 * self.ema1[0] - self.ema2[0]
69
+
70
+ def once(self, start, end):
71
+ """Calculate DEMA in runonce mode."""
72
+ ema1_array = self.ema1.lines[0].array
73
+ ema2_array = self.ema2.lines[0].array
74
+ larray = self.lines.dema.array
75
+
76
+ while len(larray) < end:
77
+ larray.append(float("nan"))
78
+
79
+ minperiod = 2 * self.p.period - 1
80
+ for i in range(min(minperiod - 1, len(ema1_array))):
81
+ if i < len(larray):
82
+ larray[i] = float("nan")
83
+
84
+ for i in range(minperiod - 1, min(end, len(ema1_array), len(ema2_array))):
85
+ ema1_val = ema1_array[i] if i < len(ema1_array) else 0.0
86
+ ema2_val = ema2_array[i] if i < len(ema2_array) else 0.0
87
+
88
+ if (
89
+ isinstance(ema1_val, float)
90
+ and math.isnan(ema1_val)
91
+ or isinstance(ema2_val, float)
92
+ and math.isnan(ema2_val)
93
+ ):
94
+ larray[i] = float("nan")
95
+ else:
96
+ larray[i] = 2.0 * ema1_val - ema2_val
97
+
98
+
99
+ # Triple Exponential Moving Average
100
+ class TripleExponentialMovingAverage(MovingAverageBase):
101
+ """
102
+ TEMA was first time introduced in 1994, in the article "Smoothing Data with
103
+ Faster-Moving Averages" by Patrick G. Mulloy in "Technical Analysis of
104
+ Stocks & Commodities" magazine.
105
+
106
+ It attempts to reduce the inherent lag associated with Moving Averages
107
+
108
+ Formula:
109
+ - ema1 = ema(data, period)
110
+ - ema2 = ema(ema1, period)
111
+ - ema3 = ema(ema2, period)
112
+ - tema = 3 * ema1 - 3 * ema2 + ema3
113
+
114
+ See:
115
+ (None)
116
+ """
117
+
118
+ alias = (
119
+ "TEMA",
120
+ "MovingAverageTripleExponential",
121
+ )
122
+
123
+ lines = ("tema",)
124
+ params = (("_movav", EMA),)
125
+
126
+ def __init__(self):
127
+ """Initialize the TEMA indicator.
128
+
129
+ Creates three EMAs for the TEMA calculation.
130
+ """
131
+ super().__init__()
132
+ self.ema1 = self.p._movav(self.data, period=self.p.period)
133
+ self.ema2 = self.p._movav(self.ema1, period=self.p.period)
134
+ self.ema3 = self.p._movav(self.ema2, period=self.p.period)
135
+ # minperiod = 3 * period - 2 for TEMA
136
+ self._minperiod = max(self._minperiod, 3 * self.p.period - 2)
137
+
138
+ def next(self):
139
+ """Calculate TEMA for the current bar.
140
+
141
+ Formula: TEMA = 3 * EMA1 - 3 * EMA2 + EMA3
142
+ """
143
+ self.lines.tema[0] = 3.0 * self.ema1[0] - 3.0 * self.ema2[0] + self.ema3[0]
144
+
145
+ def once(self, start, end):
146
+ """Calculate TEMA in runonce mode."""
147
+ ema1_array = self.ema1.lines[0].array
148
+ ema2_array = self.ema2.lines[0].array
149
+ ema3_array = self.ema3.lines[0].array
150
+ larray = self.lines.tema.array
151
+
152
+ while len(larray) < end:
153
+ larray.append(float("nan"))
154
+
155
+ minperiod = 3 * self.p.period - 2
156
+ for i in range(min(minperiod - 1, len(ema1_array))):
157
+ if i < len(larray):
158
+ larray[i] = float("nan")
159
+
160
+ for i in range(minperiod - 1, min(end, len(ema1_array), len(ema2_array), len(ema3_array))):
161
+ ema1_val = ema1_array[i] if i < len(ema1_array) else 0.0
162
+ ema2_val = ema2_array[i] if i < len(ema2_array) else 0.0
163
+ ema3_val = ema3_array[i] if i < len(ema3_array) else 0.0
164
+
165
+ if (
166
+ isinstance(ema1_val, float)
167
+ and math.isnan(ema1_val)
168
+ or isinstance(ema2_val, float)
169
+ and math.isnan(ema2_val)
170
+ or isinstance(ema3_val, float)
171
+ and math.isnan(ema3_val)
172
+ ):
173
+ larray[i] = float("nan")
174
+ else:
175
+ larray[i] = 3.0 * ema1_val - 3.0 * ema2_val + ema3_val