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,226 @@
1
+ #!/usr/bin/env python
2
+ """Annual Return Analyzer Module - Annual return calculation.
3
+
4
+ This module provides the AnnualReturn analyzer for calculating
5
+ year-by-year returns of a strategy.
6
+
7
+ Classes:
8
+ AnnualReturn: Analyzer that calculates annual returns.
9
+
10
+ Example:
11
+ >>> cerebro = bt.Cerebro()
12
+ >>> cerebro.addanalyzer(bt.analyzers.AnnualReturn, _name='annret')
13
+ >>> results = cerebro.run()
14
+ >>> print(results[0].analyzers.annret.get_analysis())
15
+ """
16
+
17
+ import math
18
+ from collections import OrderedDict
19
+
20
+ from ..analyzer import Analyzer
21
+ from ..utils.date import num2date
22
+ from ..utils.log_message import get_logger
23
+ from ..utils.py3 import range
24
+
25
+ logger = get_logger(__name__)
26
+
27
+
28
+ # Calculate annual returns. The algorithm implementation is somewhat complex, so a pandas-based version MyAnnualReturn was written later with much simpler logic
29
+ class AnnualReturn(Analyzer):
30
+ """
31
+ This analyzer calculates the AnnualReturns by looking at the beginning
32
+ and end of the year
33
+
34
+ Params:
35
+
36
+ - (None)
37
+
38
+ Member Attributes:
39
+
40
+ - ``rets``: list of calculated annual returns
41
+
42
+ - ``ret``: dictionary (key: year) of annual returns
43
+
44
+ **get_analysis**:
45
+
46
+ - Returns a dictionary of annual returns (key: year)
47
+ """
48
+
49
+ def __init__(self):
50
+ """Initialize the AnnualReturn analyzer.
51
+
52
+ Initializes cache lists for storing dates and values during backtesting.
53
+ """
54
+ super().__init__()
55
+ # Cache data
56
+ self._dt_cache = []
57
+ self._value_cache = []
58
+
59
+ def next(self):
60
+ """Cache current date and account value on each bar.
61
+
62
+ Stores the current datetime and portfolio value for later
63
+ annual return calculation.
64
+ """
65
+ # Cache current date and account value each time next is called
66
+ dt_val = self.data.datetime[0]
67
+ value_val = self.strategy.broker.getvalue()
68
+ self._dt_cache.append(dt_val)
69
+ self._value_cache.append(value_val)
70
+
71
+ def stop(self):
72
+ """Calculate annual returns from cached data.
73
+
74
+ Iterates through cached date-value pairs to calculate returns
75
+ for each calendar year. Stores results in self.rets (list) and
76
+ self.ret (dictionary keyed by year).
77
+ """
78
+ # Must have stats.broker
79
+ # Current year
80
+ cur_year = -1
81
+ # Start value
82
+ value_start = 0.0
83
+ # End value
84
+ value_end = 0.0
85
+ # Save return data
86
+ setattr(self, "rets", [])
87
+ setattr(self, "ret", OrderedDict())
88
+
89
+ # Calculate using cached data
90
+ for i in range(len(self._dt_cache)):
91
+ dt_val = self._dt_cache[i]
92
+ value_cur = self._value_cache[i]
93
+
94
+ # Convert date
95
+ try:
96
+ dt = num2date(dt_val)
97
+ except (ValueError, TypeError, OverflowError) as e:
98
+ logger.warning("Failed to convert date value %s: %s", dt_val, e)
99
+ continue
100
+
101
+ # If the year at index i is greater than current year, if current year > 0, calculate return and save to self.ret, and start value equals end value
102
+ # When years are not equal, it indicates current i is a new year
103
+ if dt.year > cur_year:
104
+ if cur_year >= 0:
105
+ annual_ret = self._safe_annual_return(value_start, value_end)
106
+ self.rets.append(annual_ret)
107
+ self.ret[cur_year] = annual_ret
108
+
109
+ # changing between real years, use last value as new start
110
+ value_start = value_end
111
+ else:
112
+ # No value set whatsoever, use the currently loaded value
113
+ value_start = value_cur
114
+
115
+ cur_year = dt.year
116
+
117
+ # No matter what, the last value is always the last loaded value
118
+ value_end = value_cur
119
+ # If current year hasn't ended and return hasn't been calculated, calculate at the end even if less than a full year
120
+ if cur_year >= 0 and cur_year not in self.ret:
121
+ # finish calculating pending data
122
+ annual_ret = self._safe_annual_return(value_start, value_end)
123
+ self.rets.append(annual_ret)
124
+ self.ret[cur_year] = annual_ret
125
+
126
+ @staticmethod
127
+ def _safe_annual_return(value_start, value_end):
128
+ """Compute (value_end/value_start - 1), returning 0.0 for any invalid
129
+ (zero/NaN/inf/complex) inputs or result. Shared by the year-boundary
130
+ and final-pending paths in stop()."""
131
+ try:
132
+ valid_values = (
133
+ value_start != 0 and math.isfinite(value_start) and math.isfinite(value_end)
134
+ )
135
+ except TypeError:
136
+ valid_values = False
137
+ if not valid_values:
138
+ return 0.0
139
+ try:
140
+ annual_ret = (value_end / value_start) - 1.0
141
+ if isinstance(annual_ret, complex) or not math.isfinite(annual_ret):
142
+ return 0.0
143
+ return annual_ret
144
+ except (ZeroDivisionError, TypeError, ValueError):
145
+ return 0.0
146
+
147
+ def get_analysis(self):
148
+ """Return the annual return analysis results.
149
+
150
+ Returns:
151
+ OrderedDict: Dictionary mapping years to their annual returns.
152
+ """
153
+ return self.ret
154
+
155
+
156
+ class MyAnnualReturn(Analyzer):
157
+ """
158
+ This analyzer calculates the AnnualReturns by looking at the beginning
159
+ and end of the year
160
+
161
+ Params:
162
+
163
+ - (None)
164
+
165
+ Member Attributes:
166
+
167
+ - ``rets``: list of calculated annual returns
168
+
169
+ - ``ret``: dictionary (key: year) of annual returns
170
+
171
+ **get_analysis**:
172
+
173
+ - Returns a dictionary of annual returns (key: year)
174
+ """
175
+
176
+ def stop(self):
177
+ """Calculate annual returns using pandas.
178
+
179
+ Uses pandas DataFrame operations to group data by year and
180
+ calculate annual returns based on beginning and ending values
181
+ for each year.
182
+
183
+ Note:
184
+ This method requires pandas to be installed.
185
+ """
186
+ # Container for saving data - dictionary
187
+ if not hasattr(self, "ret"):
188
+ setattr(self, "ret", OrderedDict())
189
+ # Get data time and convert to date
190
+ dt_list = self.data.datetime.get(0, size=len(self.data))
191
+ dt_list = [num2date(i) for i in dt_list]
192
+ # Get account assets
193
+ value_list = self.strategy.stats.broker.value.get(0, size=len(self.data))
194
+ # Convert to pandas format
195
+ import pandas as pd
196
+
197
+ df = pd.DataFrame([dt_list, value_list]).T
198
+ df.columns = ["datetime", "value"]
199
+ df["pre_value"] = df["value"].shift(1)
200
+ # Calculate simple returns for each year
201
+ df["year"] = [i.year for i in df["datetime"]]
202
+ for year, data in df.groupby("year"):
203
+ begin_value = list(data["pre_value"])[0]
204
+ end_value = list(data["value"])[-1]
205
+ try:
206
+ valid_values = math.isfinite(begin_value) and math.isfinite(end_value)
207
+ except TypeError:
208
+ valid_values = False
209
+ if not valid_values or begin_value == 0:
210
+ annual_return = 0.0
211
+ else:
212
+ try:
213
+ annual_return = (end_value / begin_value) - 1
214
+ if isinstance(annual_return, complex) or not math.isfinite(annual_return):
215
+ annual_return = 0.0
216
+ except (ZeroDivisionError, TypeError, ValueError):
217
+ annual_return = 0.0
218
+ self.ret[year] = annual_return
219
+
220
+ def get_analysis(self):
221
+ """Return the annual return analysis results.
222
+
223
+ Returns:
224
+ OrderedDict: Dictionary mapping years to their annual returns.
225
+ """
226
+ return self.ret
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env python
2
+ """Calmar Ratio Analyzer Module - Calmar ratio calculation.
3
+
4
+ This module provides the Calmar analyzer for calculating the Calmar
5
+ ratio (annual return divided by maximum drawdown).
6
+
7
+ Classes:
8
+ Calmar: Analyzer that calculates Calmar ratio.
9
+
10
+ Example:
11
+ >>> cerebro = bt.Cerebro()
12
+ >>> cerebro.addanalyzer(bt.analyzers.Calmar, _name='calmar')
13
+ >>> results = cerebro.run()
14
+ >>> print(results[0].analyzers.calmar.get_analysis())
15
+ """
16
+
17
+ import collections
18
+ import math
19
+
20
+ from ..analyzer import TimeFrameAnalyzerBase
21
+ from ..dataseries import TimeFrame
22
+ from ..metabase import OwnerContext
23
+ from .drawdown import TimeDrawDown
24
+
25
+ __all__ = ["Calmar"]
26
+
27
+
28
+ # Calculate Calmar ratio. Overall, this Calmar calculation is not very successful, or the analyzer/observer series indicators are not very efficient in usage
29
+ # Consider creating an analysis module similar to pyfolio
30
+ class Calmar(TimeFrameAnalyzerBase):
31
+ """This analyzer calculates the CalmarRatio
32
+ timeframe which can be different from the one used in the underlying data
33
+ Params:
34
+
35
+ - ``timeframe`` (default: ``None``)
36
+ If ``None`` the ``timeframe`` of the first data in the system will be
37
+ used
38
+
39
+ Pass ``TimeFrame.NoTimeFrame`` to consider the entire dataset with no
40
+ time constraints
41
+
42
+ - ``compression`` (default: ``None``)
43
+
44
+ Only used for sub-day timeframes to, for example, work on an hourly
45
+ timeframe by specifying "TimeFrame.Minutes" and 60 as compression
46
+
47
+ If compression is None, then the compression of the first data in the system will be
48
+ used
49
+ - *None*
50
+
51
+ - ``fund`` (default: ``None``)
52
+
53
+ If ``None``, the actual mode of the broker (fundmode - True/False) will
54
+ be autodetected to decide if the returns are based on the total net
55
+ asset value or on the fund value. See ``set_fundmode`` in the broker
56
+ documentation
57
+
58
+ Set it to ``True`` or ``False`` for a specific behavior
59
+
60
+ See also:
61
+
62
+ - https://en.wikipedia.org/wiki/Calmar_ratio
63
+
64
+ Methods:
65
+ - ``get_analysis``
66
+
67
+ Returns a OrderedDict with a key for the time period and the
68
+ corresponding rolling Calmar ratio
69
+
70
+ Attributes:
71
+ - ``calmar`` the latest calculated calmar ratio
72
+ """
73
+
74
+ # Modules used
75
+ packages = (
76
+ "collections",
77
+ "math",
78
+ )
79
+ # Parameters
80
+ params = (
81
+ ("timeframe", TimeFrame.Months), # default in calmar
82
+ ("period", 36),
83
+ ("fund", None),
84
+ )
85
+
86
+ # Calculate max drawdown
87
+ def __init__(self, *args, **kwargs):
88
+ """Initialize the Calmar analyzer.
89
+
90
+ Args:
91
+ *args: Positional arguments.
92
+ **kwargs: Keyword arguments for analyzer parameters.
93
+ """
94
+ # Call parent class __init__ method to support timeframe and compression parameters
95
+ super().__init__(*args, **kwargs)
96
+
97
+ self.calmar = None
98
+ self._fundmode = None
99
+ self._values = None
100
+ self._mdd = None
101
+ # Use OwnerContext so child analyzer can find this as its parent
102
+ with OwnerContext.set_owner(self):
103
+ self._maxdd = TimeDrawDown(timeframe=self.p.timeframe, compression=self.p.compression)
104
+
105
+ # Start
106
+ def start(self):
107
+ """Initialize the analyzer at the start of the backtest.
108
+
109
+ Sets up the maximum drawdown tracking, value history queue,
110
+ and fund mode.
111
+ """
112
+ # Max drawdown rate
113
+ self._mdd = float("-inf")
114
+ # Double-ended queue, saves period values, default is 36
115
+ self._values = collections.deque([float("Nan")] * self.p.period, maxlen=self.p.period)
116
+ # fundmode
117
+ if self.p.fund is None:
118
+ self._fundmode = self.strategy.broker.fundmode
119
+ else:
120
+ self._fundmode = self.p.fund
121
+ # Add different values to self._values based on fundmode
122
+ if not self._fundmode:
123
+ self._values.append(self.strategy.broker.getvalue())
124
+ else:
125
+ self._values.append(self.strategy.broker.fundvalue)
126
+
127
+ def on_dt_over(self):
128
+ """Calculate Calmar ratio when timeframe period ends.
129
+
130
+ Updates maximum drawdown and calculates Calmar ratio as
131
+ annualized return divided by maximum drawdown.
132
+ """
133
+ # Max drawdown rate
134
+ self._mdd = max(self._mdd, self._maxdd.maxdd)
135
+ # Add value to self._values
136
+ if not self._fundmode:
137
+ self._values.append(self.strategy.broker.getvalue())
138
+ else:
139
+ self._values.append(self.strategy.broker.fundvalue)
140
+ # Calculate average monthly return by default
141
+ try:
142
+ ratio = self._values[-1] / self._values[0]
143
+ if isinstance(ratio, complex) or not math.isfinite(ratio) or ratio <= 0:
144
+ raise ValueError(f"invalid calmar ratio input: {ratio}")
145
+ rann = math.log(ratio) / len(self._values)
146
+ if not math.isfinite(rann):
147
+ raise ValueError(f"invalid calmar annualized return: {rann}")
148
+ except (ZeroDivisionError, TypeError, ValueError):
149
+ rann = 0.0
150
+ # Calculate Calmar indicator
151
+ try:
152
+ self.calmar = calmar = rann / (self._mdd or float("Inf"))
153
+ except (ZeroDivisionError, TypeError, ValueError):
154
+ self.calmar = calmar = 0.0
155
+ if isinstance(calmar, complex) or not math.isfinite(calmar):
156
+ self.calmar = calmar = 0.0
157
+ # Save result
158
+ self.rets[self.dtkey] = calmar
159
+
160
+ def stop(self):
161
+ """Finalize the analysis when backtest ends.
162
+
163
+ Triggers one final Calmar ratio calculation.
164
+ """
165
+ self.on_dt_over() # update last values
@@ -0,0 +1,287 @@
1
+ #!/usr/bin/env python
2
+ """DrawDown Analyzer Module - Drawdown statistics calculation.
3
+
4
+ This module provides analyzers for calculating drawdown statistics including
5
+ current drawdown, maximum drawdown, and drawdown duration.
6
+
7
+ Classes:
8
+ DrawDown: Analyzer that calculates drawdown statistics.
9
+ TimeDrawDown: Time-frame based drawdown analyzer.
10
+
11
+ Example:
12
+ >>> cerebro = bt.Cerebro()
13
+ >>> cerebro.addanalyzer(bt.analyzers.DrawDown, _name='dd')
14
+ >>> results = cerebro.run()
15
+ >>> print(results[0].analyzers.dd.get_analysis())
16
+ """
17
+
18
+ import math
19
+
20
+ from ..analyzer import Analyzer, TimeFrameAnalyzerBase
21
+ from ..mathsupport import is_finite_real
22
+ from ..utils import AutoOrderedDict
23
+
24
+ __all__ = ["DrawDown", "TimeDrawDown"]
25
+
26
+
27
+ # Analyze drawdown situation
28
+ class DrawDown(Analyzer):
29
+ """This analyzer calculates trading system drawdowns stats such as drawdown
30
+ values in %s and in dollars, max drawdown in %s and in dollars, drawdown
31
+ length and drawdown max length
32
+
33
+ Params:
34
+
35
+ - ``fund`` (default: ``None``)
36
+
37
+ If ``None``, the actual mode of the broker (fundmode - True/False) will
38
+ be autodetected to decide if the returns are based on the total net
39
+ asset value or on the fund value. See ``set_fundmode`` in the broker
40
+ documentation
41
+
42
+ Set it to ``True`` or ``False`` for a specific behavior
43
+
44
+ Methods:
45
+
46
+ - ``get_analysis``
47
+
48
+ Returns a dictionary (with . notation support and subdctionaries) with
49
+ drawdown stats as values, the following keys/attributes are available:
50
+
51
+ - ``drawdown`` - drawdown value in 0.xx %
52
+ - ``moneydown`` - drawdown value in monetary units
53
+ - ``len`` - drawdown length
54
+
55
+ - ``max.drawdown`` - max drawdown value in 0.xx %
56
+ - ``max.moneydown`` - max drawdown value in monetary units
57
+ - ``max.len`` - max drawdown length
58
+ """
59
+
60
+ params = (("fund", None),)
61
+
62
+ # Start, get fundmode
63
+ def start(self):
64
+ """Initialize the analyzer at the start of the backtest.
65
+
66
+ Sets the fund mode based on parameters or broker settings.
67
+ """
68
+ super().start()
69
+ if self.p.fund is None:
70
+ # self._fundmode = self.strategy.broker.fundmode
71
+ setattr(self, "_fundmode", self.strategy.broker.fundmode)
72
+ else:
73
+ # self._fundmode = self.p.fund
74
+ setattr(self, "_fundmode", self.p.fund)
75
+
76
+ # Create indicator values to analyze
77
+ def create_analysis(self):
78
+ """Create the analysis result data structure.
79
+
80
+ Initializes the results dictionary with all drawdown metrics set to zero.
81
+ """
82
+ self.rets = AutoOrderedDict() # dict with. notation
83
+
84
+ self.rets.len = 0
85
+ self.rets.drawdown = 0.0
86
+ self.rets.moneydown = 0.0
87
+
88
+ self.rets.max.len = 0.0
89
+ self.rets.max.drawdown = 0.0
90
+ self.rets.max.moneydown = 0.0
91
+
92
+ self._maxvalue = float("-inf") # any value will outdo it
93
+
94
+ # Stop
95
+ def stop(self):
96
+ """Finalize the analysis when backtest ends.
97
+
98
+ Closes the results dictionary to prevent further modifications.
99
+ """
100
+ self.rets._close() # . notation cannot create more keys
101
+
102
+ # Notify fund situation
103
+ def notify_fund(self, cash, value, fundvalue, shares):
104
+ """Update drawdown calculation with current fund values.
105
+
106
+ Args:
107
+ cash: Current cash amount.
108
+ value: Current portfolio value.
109
+ fundvalue: Current fund value.
110
+ shares: Number of fund shares.
111
+ """
112
+ current_value = value if not self._fundmode else fundvalue
113
+ self._value = current_value
114
+ if is_finite_real(current_value):
115
+ if not is_finite_real(self._maxvalue):
116
+ self._maxvalue = current_value
117
+ else:
118
+ self._maxvalue = max(self._maxvalue, current_value)
119
+ elif not is_finite_real(self._maxvalue):
120
+ self._maxvalue = 0.0
121
+
122
+ def next(self):
123
+ """Calculate drawdown for the current period.
124
+
125
+ Updates current and maximum drawdown values and lengths.
126
+ """
127
+ # PERFORMANCE OPTIMIZATION: Cache attribute access to reduce lookups
128
+ # Called 688K+ times, attribute caching helps
129
+ r = self.rets
130
+ maxvalue = self._maxvalue
131
+ value = self._value
132
+ r_max = r.max
133
+
134
+ # calculate current drawdown values
135
+ if not (is_finite_real(maxvalue) and is_finite_real(value)):
136
+ moneydown = 0.0
137
+ drawdown = 0.0
138
+ else:
139
+ moneydown = maxvalue - value
140
+ drawdown = 100.0 * moneydown / maxvalue if maxvalue else 0.0
141
+ if isinstance(moneydown, complex) or not math.isfinite(moneydown):
142
+ moneydown = 0.0
143
+ if isinstance(drawdown, complex) or not math.isfinite(drawdown):
144
+ drawdown = 0.0
145
+
146
+ r.moneydown = moneydown
147
+ r.drawdown = drawdown
148
+
149
+ # maximum drawdown values
150
+ if moneydown > r_max.moneydown:
151
+ r_max.moneydown = moneydown
152
+ if drawdown > r_max.drawdown:
153
+ r_max.drawdown = drawdown
154
+
155
+ r.len = r.len + 1 if drawdown else 0
156
+ if r.len > r_max.len:
157
+ r_max.len = r.len
158
+
159
+
160
+ # Analyze time drawdown situation (max drawdown)
161
+ class TimeDrawDown(TimeFrameAnalyzerBase):
162
+ """This analyzer calculates trading system drawdowns on the chosen
163
+ timeframe which can be different from the one used in the underlying data
164
+ Params:
165
+
166
+ - ``timeframe`` (default: ``None``)
167
+ If ``None`` the ``timeframe`` of the 1st data in the system will be
168
+ used
169
+
170
+ Pass ``TimeFrame.NoTimeFrame`` to consider the entire dataset with no
171
+ time constraints
172
+
173
+ - ``compression`` (default: ``None``)
174
+
175
+ Only used for sub-day timeframes to, for example, work on an hourly
176
+ timeframe by specifying "TimeFrame.Minutes" and 60 as compression
177
+
178
+ If None, then the compression of the 1st data of the system will be
179
+ used
180
+ - *None*
181
+
182
+ - ``fund`` (default: ``None``)
183
+
184
+ If ``None``, the actual mode of the broker (fundmode - True/False) will
185
+ be autodetected to decide if the returns are based on the total net
186
+ asset value or on the fund value. See ``set_fundmode`` in the broker
187
+ documentation
188
+
189
+ Set it to ``True`` or ``False`` for a specific behavior
190
+
191
+ Methods:
192
+
193
+ - ``get_analysis``
194
+
195
+ Returns a dictionary (with . notation support and subdctionaries) with
196
+ drawdown stats as values, the following keys/attributes are available:
197
+
198
+ - ``drawdown`` - drawdown value in 0.xx %
199
+ - ``maxdrawdown`` - drawdown value in monetary units
200
+ - ``maxdrawdownperiod`` - drawdown length
201
+
202
+ - Those are available during runs as attributes
203
+ - ``dd``
204
+ - ``maxdd``
205
+ - ``maxddlen``
206
+ """
207
+
208
+ params = (("fund", None),)
209
+
210
+ def __init__(self, *args, **kwargs):
211
+ """Initialize the TimeDrawDown analyzer.
212
+
213
+ Args:
214
+ *args: Positional arguments.
215
+ **kwargs: Keyword arguments for analyzer parameters.
216
+ """
217
+ # Call parent class __init__ method to support timeframe and compression parameters
218
+ super().__init__(*args, **kwargs)
219
+
220
+ self.ddlen = None
221
+ self.peak = None
222
+ self.maxddlen = None
223
+ self.maxdd = None
224
+ self.dd = None
225
+ self._fundmode = None
226
+
227
+ def start(self):
228
+ """Initialize the analyzer at the start of the backtest.
229
+
230
+ Sets the fund mode and initializes drawdown tracking variables.
231
+ """
232
+ super().start()
233
+ # fundmode
234
+ if self.p.fund is None:
235
+ self._fundmode = self.strategy.broker.fundmode
236
+ else:
237
+ self._fundmode = self.p.fund
238
+ # Initialize parameters
239
+ self.dd = 0.0
240
+ self.maxdd = 0.0
241
+ self.maxddlen = 0
242
+ self.peak = float("-inf")
243
+ self.ddlen = 0
244
+
245
+ # Calculate max drawdown and max drawdown length
246
+ def on_dt_over(self):
247
+ """Called when a datetime period is over.
248
+
249
+ Updates drawdown calculations for the timeframe period.
250
+ """
251
+ if not self._fundmode:
252
+ value = self.strategy.broker.getvalue()
253
+ else:
254
+ value = self.strategy.broker.fundvalue
255
+ value_valid = is_finite_real(value)
256
+ if not is_finite_real(self.peak):
257
+ self.peak = 0.0
258
+
259
+ # update the maximum seen peak
260
+ if value_valid and value > self.peak:
261
+ self.peak = value
262
+ self.ddlen = 0 # start of streak
263
+
264
+ # calculate the current drawdown
265
+ try:
266
+ if value_valid and self.peak:
267
+ self.dd = dd = 100.0 * (self.peak - value) / self.peak
268
+ if isinstance(dd, complex) or not math.isfinite(dd):
269
+ self.dd = dd = 0.0
270
+ else:
271
+ self.dd = dd = 0.0
272
+ except (TypeError, ValueError, ZeroDivisionError):
273
+ self.dd = dd = 0.0
274
+ self.ddlen += bool(dd) # if peak == value -> dd = 0
275
+
276
+ # update the maxdrawdown if needed
277
+ self.maxdd = max(self.maxdd if is_finite_real(self.maxdd) else 0.0, dd)
278
+ self.maxddlen = max(self.maxddlen, self.ddlen)
279
+
280
+ # When stopping, add max drawdown and max drawdown length to dictionary
281
+ def stop(self):
282
+ """Finalize the analysis when backtest ends.
283
+
284
+ Stores the maximum drawdown and maximum drawdown period.
285
+ """
286
+ self.rets["maxdrawdown"] = self.maxdd
287
+ self.rets["maxdrawdownperiod"] = self.maxddlen