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,192 @@
1
+ #!/usr/bin/env python
2
+ """TimeReturn Analyzer Module - Time-based returns calculation.
3
+
4
+ This module provides the TimeReturn analyzer for calculating returns
5
+ over specified time periods.
6
+
7
+ Classes:
8
+ TimeReturn: Analyzer that calculates returns by timeframe.
9
+
10
+ Example:
11
+ >>> cerebro = bt.Cerebro()
12
+ >>> cerebro.addanalyzer(bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Years)
13
+ """
14
+
15
+ import math
16
+
17
+ from ..analyzer import TimeFrameAnalyzerBase
18
+
19
+
20
+ class TimeReturn(TimeFrameAnalyzerBase):
21
+ """This analyzer calculates the Returns by looking at the beginning
22
+ and end of the timeframe
23
+
24
+ Params:
25
+
26
+ - ``timeframe`` (default: ``None``)
27
+ If ``None`` the ``timeframe`` of the first data in the system will be
28
+ used
29
+
30
+ Pass ``TimeFrame.NoTimeFrame`` to consider the entire dataset with no
31
+ time constraints
32
+
33
+ - ``compression`` (default: ``None``)
34
+
35
+ Only used for sub-day timeframes to, for example, work on an hourly
36
+ timeframe by specifying "TimeFrame.Minutes" and 60 as compression
37
+
38
+ If `None`, then the compression of the first data in the system will be
39
+ used
40
+
41
+ - ``data`` (default: ``None``)
42
+
43
+ Reference asset to track instead of the portfolio value.
44
+
45
+ - Note:: this data must have been added to a ``cerebro`` instance with
46
+ ``addata``, ``resampledata`` or ``replaydata``
47
+
48
+ - ``firstopen`` (default: ``True``)
49
+
50
+ When tracking the returns of `data` the following is done when
51
+ crossing a timeframe boundary, for example, ``Years``:
52
+
53
+ - Last ``close`` the previous year is used as the reference price to
54
+ see the return in the current year
55
+
56
+ The problem is the first calculation, because the data has** no
57
+ previous** closing price.As such, and when this parameter is `True`,
58
+ the *opening* price will be used for the first calculation.
59
+
60
+ This requires the data feed to have an ``open`` price (for ``close``
61
+ the standard [0] notations will be used without a reference to a field
62
+ price)
63
+
64
+ Else the initial close will be used.
65
+ # When calculating returns for the first period, whether to use the first opening price. If parameter is False, the first closing price will be used
66
+
67
+ - ``fund`` (default: ``None``)
68
+
69
+ If `None`, the actual mode of the broker (fundmode - True/False) will
70
+ be autodetected to decide if the returns are based on the total net
71
+ asset value or on the fund value. See ``set_fundmode`` in the broker
72
+ documentation
73
+
74
+ Set it to ``True`` or ``False`` for a specific behavior
75
+
76
+ Methods:
77
+
78
+ - Get_analysis
79
+
80
+ Returns a dictionary with returns as values and the datetime points for
81
+ each return as keys
82
+ """
83
+
84
+ # Parameters
85
+ params = (
86
+ ("data", None),
87
+ ("firstopen", True),
88
+ ("fund", None),
89
+ )
90
+
91
+ # __init__ method to support parameter initialization after metaclass removal
92
+ def __init__(self, *args, **kwargs):
93
+ """Initialize the TimeReturn analyzer.
94
+
95
+ Args:
96
+ *args: Positional arguments.
97
+ **kwargs: Keyword arguments for analyzer parameters.
98
+ """
99
+ super().__init__(*args, **kwargs)
100
+
101
+ # Start
102
+ def start(self):
103
+ """Initialize the analyzer at the start of the backtest.
104
+
105
+ Sets the fund mode and initializes the starting value for return
106
+ calculations.
107
+ """
108
+ super().start()
109
+ if self.p.fund is None:
110
+ self._fundmode = self.strategy.broker.fundmode
111
+ else:
112
+ self._fundmode = self.p.fund
113
+ # PERFORMANCE OPTIMIZATION: Cache p.data reference (called 691K+ times)
114
+ self._p_data = self.p.data
115
+ # Start value
116
+ self._value_start = 0.0
117
+ # End value
118
+ self._lastvalue = None
119
+ # If parameter data is None
120
+ if self._p_data is None:
121
+ # keep the initial portfolio value if not tracing a data
122
+ if not self._fundmode:
123
+ self._lastvalue = self.strategy.broker.getvalue()
124
+ else:
125
+ self._lastvalue = self.strategy.broker.fundvalue
126
+
127
+ # Notify fund information
128
+ def notify_fund(self, cash, value, fundvalue, shares):
129
+ """Update current value based on fund notification.
130
+
131
+ Args:
132
+ cash: Current cash amount.
133
+ value: Current portfolio value.
134
+ fundvalue: Current fund value.
135
+ shares: Number of fund shares.
136
+ """
137
+ # PERFORMANCE OPTIMIZATION: Use cached _p_data reference
138
+ p_data = self._p_data
139
+ if not self._fundmode:
140
+ # Record current value
141
+ if p_data is None:
142
+ self._value = value # the portofolio value if tracking no data
143
+ else:
144
+ self._value = p_data[0] # the data value if tracking data
145
+ else:
146
+ if p_data is None:
147
+ self._value = fundvalue # the fund value if tracking no data
148
+ else:
149
+ self._value = p_data[0] # the data value if tracking data
150
+
151
+ # On datetime over
152
+ def on_dt_over(self):
153
+ """Handle timeframe boundary crossing.
154
+
155
+ Updates the starting value for return calculation when crossing
156
+ into a new timeframe period.
157
+ """
158
+ # next is called in a new timeframe period
159
+ # PERFORMANCE OPTIMIZATION: Use cached _p_data reference
160
+ p_data = self._p_data
161
+ if p_data is None or self._lastvalue is not None:
162
+ self._value_start = self._lastvalue # update value_start to last
163
+
164
+ else:
165
+ # The 1st tick has no previous reference, use the opening price
166
+ if self.p.firstopen:
167
+ self._value_start = p_data.open[0]
168
+ else:
169
+ self._value_start = p_data[0]
170
+
171
+ # Call next
172
+ def next(self):
173
+ """Calculate and store the return for the current period.
174
+
175
+ Calculates the return as (current_value / start_value) - 1 and
176
+ stores it in the results dictionary keyed by datetime.
177
+ """
178
+ # Calculate the return
179
+ super().next()
180
+ # self.dtkey is an attribute set in analyzer, usually the end date of a period
181
+ if self._value_start:
182
+ try:
183
+ ret = (self._value / self._value_start) - 1.0
184
+ if isinstance(ret, complex) or not math.isfinite(ret):
185
+ ret = 0.0
186
+ except (ZeroDivisionError, TypeError, ValueError):
187
+ ret = 0.0
188
+ self.rets[self.dtkey] = ret
189
+ else:
190
+ self.rets[self.dtkey] = 0.0
191
+ # self.rets[self.dtkey] = (float(self._value) / float(self._value_start)) - 1.0
192
+ self._lastvalue = self._value # keep last value
@@ -0,0 +1,75 @@
1
+ """TotalValue Analyzer Module - Portfolio value tracking.
2
+
3
+ This module provides the TotalValue analyzer for tracking the total
4
+ portfolio value over time.
5
+
6
+ Classes:
7
+ TotalValue: Analyzer that records portfolio value at each step.
8
+
9
+ Example:
10
+ >>> cerebro = bt.Cerebro()
11
+ >>> cerebro.addanalyzer(bt.analyzers.TotalValue, _name='val')
12
+ >>> results = cerebro.run()
13
+ >>> print(results[0].analyzers.val.get_analysis())
14
+ """
15
+
16
+ import math
17
+ from collections import OrderedDict
18
+ from typing import Optional
19
+
20
+ from ..analyzer import Analyzer
21
+
22
+
23
+ def _finite_real_or_zero(value):
24
+ try:
25
+ if isinstance(value, complex) or not math.isfinite(value):
26
+ return 0.0
27
+ except TypeError:
28
+ return 0.0
29
+ return value
30
+
31
+
32
+ class TotalValue(Analyzer):
33
+ """This analyzer will get total value from every next.
34
+
35
+ Params:
36
+ Methods:
37
+
38
+ - Get_analysis
39
+
40
+ Returns a dictionary with returns as values and the datetime points for
41
+ each return as keys
42
+ """
43
+
44
+ params = ()
45
+ rets: Optional[dict] = None
46
+
47
+ def start(self):
48
+ """Initialize the analyzer at the start of the backtest.
49
+
50
+ Creates the ordered dictionary to store value history.
51
+ """
52
+ super().start()
53
+ self.rets = OrderedDict()
54
+ # PERFORMANCE OPTIMIZATION: Cache broker reference
55
+ self._broker = self.strategy.broker
56
+
57
+ # PERFORMANCE OPTIMIZATION: Cache attribute access, called 522K+ times
58
+ def next(self):
59
+ """Record the total portfolio value for the current bar.
60
+
61
+ Gets the current portfolio value from the broker and stores it
62
+ keyed by datetime.
63
+ """
64
+ # Calculate the return
65
+ super().next()
66
+ # Cache attribute access for performance
67
+ self.rets[self.datas[0].datetime.datetime()] = _finite_real_or_zero(self._broker.getvalue())
68
+
69
+ def get_analysis(self):
70
+ """Return the total value analysis results.
71
+
72
+ Returns:
73
+ OrderedDict: Dictionary mapping datetimes to portfolio values.
74
+ """
75
+ return self.rets
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env python
2
+ """Trade Analyzer Module - Detailed trade statistics.
3
+
4
+ This module provides the TradeAnalyzer for calculating comprehensive
5
+ trade statistics including win/loss ratios, streaks, and PnL metrics.
6
+
7
+ Classes:
8
+ TradeAnalyzer: Analyzer that calculates detailed trade statistics.
9
+
10
+ Example:
11
+ >>> cerebro = bt.Cerebro()
12
+ >>> cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='ta')
13
+ >>> results = cerebro.run()
14
+ >>> print(results[0].analyzers.ta.get_analysis())
15
+ """
16
+
17
+ from ..analyzer import Analyzer
18
+ from ..utils import AutoDict, AutoOrderedDict
19
+ from ..utils.py3 import MAXINT
20
+
21
+
22
+ # Analyze trades
23
+ class TradeAnalyzer(Analyzer):
24
+ """
25
+ Provides statistics on closed trades (keeps also the count of open ones)
26
+
27
+ - Total Open/Closed Trades
28
+
29
+ - Streak Won/Lost Current/Longest
30
+
31
+ - ProfitAndLoss Total/Average
32
+
33
+ - Won/Lost Count/ Total PNL/ Average PNL / Max PNL
34
+
35
+ - Long/Short Count/ Total PNL / Average PNL / Max PNL
36
+
37
+ - Won/Lost Count/ Total PNL/ Average PNL / Max PNL
38
+
39
+ - Length (bars in the market)
40
+
41
+ - Total/Average/Max/Min
42
+
43
+ - Won/Lost Total/Average/Max/Min
44
+
45
+ - Long/Short Total/Average/Max/Min
46
+
47
+ - Won/Lost Total/Average/Max/Min
48
+
49
+ Note:
50
+
51
+ The analyzer uses an autodict for the fields, which means that if no
52
+ trades are executed, no statistics will be generated.
53
+
54
+ In that case, there will be a single field/subfield in the dictionary
55
+ returned by ``get_analysis``, namely:
56
+
57
+ - Dictname['total']['total'] which will have a value of 0 (the field is
58
+ also reachable with dot notation dictname.total.total
59
+ """
60
+
61
+ # rets is created in create_analysis(); declared here for typing only.
62
+ rets: AutoOrderedDict
63
+
64
+ # Create analysis
65
+ def create_analysis(self):
66
+ """Create the analysis result data structure.
67
+
68
+ Initializes the AutoOrderedDict with a total counter set to zero.
69
+ """
70
+ self.rets = AutoOrderedDict()
71
+ self.rets.total.total = 0
72
+
73
+ # Stop
74
+ def stop(self):
75
+ """Finalize the analysis when backtest ends.
76
+
77
+ Closes the results dictionary to prevent further modifications.
78
+ """
79
+ super().stop()
80
+ self.rets._close()
81
+
82
+ # Trade notification
83
+ def notify_trade(self, trade):
84
+ """Process trade notifications to build detailed statistics.
85
+
86
+ Updates all trade statistics including win/loss counts, streaks,
87
+ PnL metrics, and trade duration for both long and short positions.
88
+
89
+ Args:
90
+ trade: The trade object with status and PnL information.
91
+ """
92
+ # If trade just opened
93
+ if trade.justopened:
94
+ # Trade just opened
95
+ self.rets.total.total += 1
96
+ self.rets.total.open += 1
97
+ # If trade is closed
98
+ elif trade.status == trade.Closed:
99
+ self._on_trade_closed(trade)
100
+
101
+ def _on_trade_closed(self, trade):
102
+ """Update all closed-trade statistics (streak / pnl / won-lost /
103
+ long-short / length) for a single closed trade.
104
+
105
+ Extracted verbatim from notify_trade's Closed branch to keep that
106
+ dispatcher trivial; no behavior change. Split into per-category
107
+ helpers (streak / pnl / won-lost / long-short / length) to reduce
108
+ complexity; the computation order and shared ``res``/``trades``
109
+ state are preserved exactly.
110
+ """
111
+ trades = self.rets
112
+
113
+ res = AutoDict()
114
+ # Trade just closed
115
+ # Profit
116
+ res.won = int(trade.pnlcomm >= 0.0)
117
+ # Loss
118
+ res.lost = int(not res.won)
119
+ # Long position
120
+ res.tlong = trade.long
121
+ # Short position
122
+ res.tshort = not trade.long
123
+ # Opened trade
124
+ trades.total.open -= 1
125
+ # Closed trade
126
+ trades.total.closed += 1
127
+
128
+ self._update_streak(trades, res)
129
+ self._update_gross_net_pnl(trades, trade)
130
+ self._update_won_lost(trades, trade, res)
131
+ self._update_long_short(trades, trade, res)
132
+ self._update_length(trades, trade)
133
+ self._update_length_won_lost(trades, trade, res)
134
+ self._update_length_long_short(trades, trade, res)
135
+
136
+ @staticmethod
137
+ def _update_streak(trades, res):
138
+ """Streak: consecutive win and loss counts."""
139
+ for wlname in ["won", "lost"]:
140
+ # Current win/loss status
141
+ wl = res[wlname]
142
+ # Current consecutive win or loss count
143
+ trades.streak[wlname].current *= wl
144
+ trades.streak[wlname].current += wl
145
+ # Get maximum consecutive win or loss count
146
+ ls = trades.streak[wlname].longest or 0
147
+ # Recalculate
148
+ trades.streak[wlname].longest = max(ls, trades.streak[wlname].current)
149
+
150
+ @staticmethod
151
+ def _update_gross_net_pnl(trades, trade):
152
+ """Aggregate gross/net total and average trade pnl."""
153
+ # Trade profit/loss
154
+ trpnl = trades.pnl
155
+ # Total trade profit/loss
156
+ trpnl.gross.total += trade.pnl
157
+ # Average profit/loss
158
+ trpnl.gross.average = trades.pnl.gross.total / trades.total.closed
159
+ # Net trade profit/loss
160
+ trpnl.net.total += trade.pnlcomm
161
+ # Average net profit/loss
162
+ trpnl.net.average = trades.pnl.net.total / trades.total.closed
163
+
164
+ @staticmethod
165
+ def _update_won_lost(trades, trade, res):
166
+ """Won/Lost statistics: counts and pnl per win/loss bucket."""
167
+ for wlname in ["won", "lost"]:
168
+ # Current win/loss
169
+ wl = res[wlname]
170
+ # Historical win/loss
171
+ trwl = trades[wlname]
172
+ # Win/loss count
173
+ trwl.total += wl # won.total / lost.total
174
+ # Total and average profit/loss
175
+ trwlpnl = trwl.pnl
176
+ pnlcomm = trade.pnlcomm * wl
177
+
178
+ trwlpnl.total += pnlcomm
179
+ trwlpnl.average = trwlpnl.total / (trwl.total or 1.0)
180
+ # Maximum profit or minimum loss (largest losing trade)
181
+ wm = trwlpnl.max or 0.0
182
+ func = max if wlname == "won" else min
183
+ trwlpnl.max = func(wm, pnlcomm)
184
+
185
+ @staticmethod
186
+ def _update_long_short(trades, trade, res):
187
+ """Long/Short statistics: counts and pnl per direction and win/loss."""
188
+ for tname in ["long", "short"]:
189
+ # Long and short
190
+ trls = trades[tname]
191
+ # Current trade's long and short
192
+ ls = res["t" + tname]
193
+ # Calculate long and short counts
194
+ trls.total += ls # long.total / short.total
195
+ # Calculate total pnl for long and short
196
+ trls.pnl.total += trade.pnlcomm * ls
197
+ # Calculate average profit for long and short
198
+ trls.pnl.average = trls.pnl.total / (trls.total or 1.0)
199
+ # Analyze win/loss status for long and short
200
+ for wlname in ["won", "lost"]:
201
+ wl = res[wlname]
202
+ pnlcomm = trade.pnlcomm * wl * ls
203
+
204
+ trls[wlname] += wl * ls # long.won / short.won
205
+
206
+ trls.pnl[wlname].total += pnlcomm
207
+ trls.pnl[wlname].average = trls.pnl[wlname].total / (trls[wlname] or 1.0)
208
+
209
+ wm = trls.pnl[wlname].max or 0.0
210
+ func = max if wlname == "won" else min
211
+ trls.pnl[wlname].max = func(wm, pnlcomm)
212
+
213
+ @staticmethod
214
+ def _update_length(trades, trade):
215
+ """Length: total/average/max/min bars across all closed trades."""
216
+ # Number of bars occupied by trade
217
+ trades.len.total += trade.barlen
218
+ # Average number of bars per trade
219
+ trades.len.average = trades.len.total / trades.total.closed
220
+ # Maximum number of bars occupied by trade
221
+ ml = trades.len.max or 0
222
+ trades.len.max = max(ml, trade.barlen)
223
+ # Minimum number of bars occupied by trade
224
+ ml = trades.len.min or MAXINT
225
+ trades.len.min = min(ml, trade.barlen)
226
+
227
+ @staticmethod
228
+ def _update_length_won_lost(trades, trade, res):
229
+ """Length split by win/loss bucket."""
230
+ # Number of bars for winning/losing trades, similar to above but separated by profit and loss
231
+ for wlname in ["won", "lost"]:
232
+ trwl = trades.len[wlname]
233
+ wl = res[wlname]
234
+
235
+ trwl.total += trade.barlen * wl
236
+ trwl.average = trwl.total / (trades[wlname].total or 1.0)
237
+
238
+ m = trwl.max or 0
239
+ trwl.max = max(m, trade.barlen * wl)
240
+ if trade.barlen * wl:
241
+ m = trwl.min or MAXINT
242
+ trwl.min = min(m, trade.barlen * wl)
243
+
244
+ @staticmethod
245
+ def _update_length_long_short(trades, trade, res):
246
+ """Length split by direction and win/loss bucket."""
247
+ # Distinguish long and short lengths
248
+ for lsname in ["long", "short"]:
249
+ trls = trades.len[lsname] # trades.len.long
250
+ ls = res["t" + lsname] # tlong/tshort
251
+
252
+ barlen = trade.barlen * ls
253
+
254
+ trls.total += barlen # trades.len.long.total
255
+ total_ls = trades[lsname].total # trades.long.total
256
+ trls.average = trls.total / (total_ls or 1.0)
257
+
258
+ # max/min
259
+ m = trls.max or 0
260
+ trls.max = max(m, barlen)
261
+ m = trls.min or MAXINT
262
+ trls.min = min(m, barlen or m)
263
+ # Distinguish winning and losing lengths for long and short
264
+ for wlname in ["won", "lost"]:
265
+ wl = res[wlname] # won/lost
266
+
267
+ barlen2 = trade.barlen * ls * wl
268
+
269
+ trls_wl = trls[wlname] # trades.len.long.won
270
+ trls_wl.total += barlen2 # trades.len.long.won.total
271
+
272
+ trls_wl.average = trls_wl.total / (trades[lsname][wlname] or 1.0)
273
+
274
+ # max/min
275
+ m = trls_wl.max or 0
276
+ trls_wl.max = max(m, barlen2)
277
+ m = trls_wl.min or MAXINT
278
+ trls_wl.min = min(m, barlen2 or m)
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env python
2
+ """Transactions Analyzer Module - Transaction logging.
3
+
4
+ This module provides the Transactions analyzer for recording all
5
+ transactions (order executions) during backtesting.
6
+
7
+ Classes:
8
+ Transactions: Analyzer that records transaction history.
9
+
10
+ Example:
11
+ >>> cerebro = bt.Cerebro()
12
+ >>> cerebro.addanalyzer(bt.analyzers.Transactions, _name='txn')
13
+ >>> results = cerebro.run()
14
+ >>> print(results[0].analyzers.txn.get_analysis())
15
+ """
16
+
17
+ import collections
18
+
19
+ from ..analyzer import Analyzer
20
+ from ..order import Order
21
+ from ..position import Position
22
+
23
+
24
+ # Transactions
25
+ class Transactions(Analyzer):
26
+ """This analyzer reports the transactions occurred with each every data in
27
+ the system
28
+
29
+ It looks at the order execution bits to create a `Position` starting from
30
+ 0 during each `next` cycle.
31
+
32
+ The result is used during next to record the transactions
33
+
34
+ Params:
35
+
36
+ - Headers (default: ``True``)
37
+
38
+ Add an initial key to the dictionary holding the results with the names
39
+ of the datas
40
+
41
+ This analyzer was modeled to facilitate the integration with
42
+ ``pyfolio``, and the header names are taken from the samples used for
43
+ it::
44
+
45
+ 'Date', 'amount', 'price', 'sid', 'symbol', 'value'
46
+
47
+ Methods:
48
+
49
+ - Get_analysis
50
+
51
+ Returns a dictionary with returns as values and the datetime points for
52
+ each return as keys
53
+ """
54
+
55
+ # Parameters
56
+ params = (
57
+ ("headers", False),
58
+ ("_pfheaders", ("date", "amount", "price", "sid", "symbol", "value")),
59
+ )
60
+
61
+ # Initialize
62
+ def __init__(self, *args, **kwargs):
63
+ """Initialize the Transactions analyzer.
64
+
65
+ Args:
66
+ *args: Positional arguments.
67
+ **kwargs: Keyword arguments for analyzer parameters.
68
+ """
69
+ # CRITICAL FIX: Call super().__init__() first to initialize self.p
70
+ super().__init__(*args, **kwargs)
71
+ self._idnames = None
72
+ self._positions = None
73
+
74
+ def start(self):
75
+ """Initialize the analyzer at the start of the backtest.
76
+
77
+ Sets up the results structure and initializes position tracking
78
+ for each data feed.
79
+ """
80
+ super().start()
81
+ # If headers is True, initialize rets
82
+ if self.p.headers:
83
+ self.rets[self.p._pfheaders[0]] = [list(self.p._pfheaders[1:])]
84
+ # Positions
85
+ self._positions = collections.defaultdict(Position)
86
+ # Index and data names
87
+ self._idnames = list(enumerate(self.strategy.getdatanames()))
88
+
89
+ # Order information processing
90
+ def notify_order(self, order):
91
+ """Process order execution notifications.
92
+
93
+ Updates the position tracking when orders are executed or partially
94
+ executed. Collected positions are recorded in the next() method.
95
+
96
+ Args:
97
+ order: The order object with execution information.
98
+ """
99
+ # An order could have several partial executions per cycle (unlikely
100
+ # but possible) and therefore: collect each new execution notification
101
+ # and let the work for the next
102
+
103
+ # We use a fresh Position object for each round to get a summary of what
104
+ # the execution bits have done in that round
105
+ # If order is not executed, ignore
106
+ if order.status not in [Order.Partial, Order.Completed]:
107
+ return # It's not an execution
108
+ # Get position of the data that generated the order
109
+ pos = self._positions[order.data._name]
110
+ # Loop
111
+ for exbit in order.executed.iterpending():
112
+ # If execution info is None, break
113
+ if exbit is None:
114
+ break # end of pending reached
115
+ # Update position information
116
+ pos.update(exbit.size, exbit.price)
117
+
118
+ # Called once per bar
119
+ def next(self):
120
+ """Record transactions for the current bar.
121
+
122
+ Collects position changes from all data feeds and records them
123
+ in the results dictionary keyed by datetime.
124
+ """
125
+ # super(Transactions, self).next() # let dtkey update
126
+ # Entries
127
+ entries = []
128
+ # For index and data names
129
+ for i, dname in self._idnames:
130
+ # Get position of the data
131
+ pos = self._positions.get(dname, None)
132
+ # If position is not None, if position is not 0, save position related data
133
+ if pos is not None:
134
+ size, price = pos.size, pos.price
135
+ if size:
136
+ entries.append([size, price, i, dname, -size * price])
137
+ # If position is not 0, update current bar's position data
138
+ if entries:
139
+ self.rets[self.strategy.datetime.datetime()] = entries
140
+ # Clear self._positions
141
+ self._positions.clear()