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,551 @@
1
+ """Cerebro event-driven engine mixin (iteration 28 split).
2
+
3
+ Moved verbatim from ``backtrader/cerebro.py``: ``_runnext`` (modern, with
4
+ the direct-load fast path) and ``_runnext_old`` (oldsync). Hot loop - any
5
+ edit here must be justified against AC28-09.
6
+ """
7
+
8
+ import datetime
9
+ from datetime import timezone
10
+
11
+ from ..brokers import BackBroker
12
+ from ..feed import AbstractDataBase
13
+ from ..strategy import Strategy
14
+ from ..utils import date2num
15
+ from ..utils.dateintern import _num2date_cached
16
+ from ..utils.log_message import get_logger
17
+
18
+ UTC = timezone.utc
19
+
20
+ # Keep the historical logger name (D28-04.6): routing/filters must not change.
21
+ logger = get_logger("backtrader.cerebro")
22
+
23
+
24
+ class RunNextMixin:
25
+ """Event-driven engine half of Cerebro (see module docstring)."""
26
+
27
+ # Old runnext method, similar to runnext
28
+ def _runnext_old(self, runstrats):
29
+ """
30
+ Actual implementation of run in full next mode. All objects have its
31
+ `next` method invoked on each data arrival
32
+ """
33
+ data0 = self.datas[0]
34
+ d0ret = True
35
+ while d0ret or d0ret is None:
36
+ lastret = False
37
+ # Notify anything from the store even before moving datas
38
+ # because datas may not move due to an error reported by the store
39
+ self._storenotify()
40
+ if self._event_stop: # stop if requested
41
+ return
42
+ self._datanotify()
43
+ if self._event_stop: # stop if requested
44
+ return
45
+
46
+ d0ret = data0.next()
47
+ if d0ret:
48
+ for data in self.datas[1:]:
49
+ if not data.next(datamaster=data0): # no delivery
50
+ data._check(forcedata=data0) # check forcing output
51
+ data.next(datamaster=data0) # retry
52
+
53
+ elif d0ret is None:
54
+ # meant for things like live feeds which may not produce a bar
55
+ # at the moment but need the loop to run for notifications and
56
+ # getting resample and others to produce timely bars
57
+ data0._check()
58
+ for data in self.datas[1:]:
59
+ data._check()
60
+ else:
61
+ lastret = data0._last()
62
+ for data in self.datas[1:]:
63
+ lastret += data._last(datamaster=data0)
64
+
65
+ if not lastret:
66
+ # Only go extra round if something was changed by "lasts"
67
+ break
68
+
69
+ # Datas may have generated a new notification after next
70
+ self._datanotify()
71
+ if self._event_stop: # stop if requested
72
+ return
73
+
74
+ self._brokernotify()
75
+ if self._event_stop: # stop if requested
76
+ return
77
+
78
+ if d0ret or lastret: # bars produced by data or filters
79
+ for strat in runstrats:
80
+ strat._next()
81
+ if self._event_stop: # stop if requested
82
+ return
83
+
84
+ self._next_writers(runstrats)
85
+
86
+ # Last notification chance before stopping
87
+ self._datanotify()
88
+ if self._event_stop: # stop if requested
89
+ return
90
+ self._storenotify()
91
+ if self._event_stop: # stop if requested
92
+ return
93
+
94
+ # runnext method, core of the framework, event-driven core for data execution
95
+ def _runnext(self, runstrats):
96
+ """Actual implementation of run in full next mode.
97
+
98
+ All objects have their ``next`` method invoked on each data arrival.
99
+
100
+ The loop has four phases per iteration:
101
+
102
+ 1. **Notification**: store and data notifications dispatched.
103
+ 2. **Feed advance**: each data feed is advanced; ``d0ret`` computed.
104
+ 3. **Time alignment**: feeds aligned to master datetime ``dt0``;
105
+ slower feeds rewound, faster feeds tick-filled.
106
+ 4. **Strategy dispatch**: timers fired, broker notified, strategies
107
+ receive ``_next()`` / ``_next_open()``.
108
+ """
109
+ try:
110
+ # Sort data by time period
111
+ datas = sorted(self.datas, key=lambda x: (x._timeframe, x._compression))
112
+ # Other data
113
+ datas1 = datas[1:]
114
+ # Main data
115
+ data0 = datas[0]
116
+ has_qcheck = any(d.p.qcheck for d in datas)
117
+ cheat_on_open = self.p.cheat_on_open
118
+ has_timers = bool(self._timers)
119
+ has_timerscheat = bool(self._timerscheat)
120
+ has_stores = bool(self.stores)
121
+ has_runwriters = bool(self.runwriters)
122
+ if len(runstrats) == 1:
123
+ single_runstrat = runstrats[0]
124
+ single_runstrat_next = single_runstrat._next
125
+ single_runstrat_next_open = single_runstrat._next_open
126
+ else:
127
+ single_runstrat = None
128
+ single_runstrat_next = None
129
+ idle_notifiers = tuple(
130
+ strat.notify_idle
131
+ for strat in runstrats
132
+ if type(strat).notify_idle is not Strategy.notify_idle
133
+ )
134
+ d0ret = True
135
+ # index for resample only, not replay
136
+ rsonly = [i for i, x in enumerate(datas) if x.resampling and not x.replaying]
137
+ # Check if only doing resample
138
+ onlyresample = len(datas) == len(rsonly)
139
+ # Check if no data needs resample
140
+ noresample = not rsonly
141
+ # Number of cloned data
142
+ clonecount = sum(d._clone for d in datas)
143
+ # Number of data
144
+ ldatas = len(datas)
145
+ single_data = ldatas == 1
146
+ single_default_datanotify = (
147
+ single_data and type(data0).get_notifications is AbstractDataBase.get_notifications
148
+ )
149
+ single_default_haslivedata = (
150
+ single_data and type(data0).haslivedata is AbstractDataBase.haslivedata
151
+ )
152
+ data0_datetime_line = data0.datetime if single_data else None
153
+ broker = self._broker
154
+ broker_next = broker.next
155
+ broker_next_without_bar = bool(getattr(broker, "next_without_bar", False))
156
+ broker_userhist = getattr(broker, "_userhist", None)
157
+ broker_fundhist = getattr(broker, "_fundhist", None)
158
+ default_broker_notifications = (
159
+ type(broker).get_notification is BackBroker.get_notification
160
+ )
161
+ default_backbroker_next = (
162
+ default_broker_notifications and type(broker).next is BackBroker.next
163
+ )
164
+ if default_broker_notifications:
165
+ broker_notifications = broker.notifs
166
+ else:
167
+ broker_notifications = None
168
+ broker_get_notification = broker.get_notification
169
+ if default_backbroker_next:
170
+ broker_pending = broker.pending
171
+ broker_submitted = broker.submitted
172
+ broker_toactivate = broker._toactivate
173
+ broker_cash_addition = broker._cash_addition
174
+ broker_dual_side_mode = broker._dual_side_mode
175
+ else:
176
+ broker_pending = None
177
+ broker_submitted = None
178
+ broker_toactivate = None
179
+ broker_cash_addition = None
180
+ broker_dual_side_mode = False
181
+ data0_direct_load = None
182
+ if single_data and not has_qcheck and single_default_haslivedata:
183
+ try:
184
+ if data0._runnext_direct_load_ready():
185
+ data0_direct_load = getattr(data0, "_runnext_direct_load", data0.load)
186
+ except AttributeError:
187
+ data0_direct_load = None
188
+ if data0_direct_load is not None and single_runstrat is not None:
189
+ try:
190
+ if (
191
+ single_runstrat._fast_simple_clock_update
192
+ and single_runstrat._single_clock_data is data0
193
+ and type(single_runstrat)._next is Strategy._next
194
+ ):
195
+ single_runstrat_next = single_runstrat._next_fast_simple_direct_clock
196
+ object.__setattr__(single_runstrat, "_next", single_runstrat_next)
197
+ except AttributeError:
198
+ logger.debug("runnext:200 ignored AttributeError")
199
+ # Number of non-cloned data
200
+ ldatas_noclones = ldatas - clonecount
201
+ # Default dt0 at max time
202
+ dt0 = date2num(datetime.datetime.max) - 2 # default at max
203
+ if (
204
+ data0_direct_load is not None
205
+ and single_runstrat_next is not None
206
+ and getattr(single_runstrat_next, "__func__", None)
207
+ is Strategy._next_fast_simple_direct_clock
208
+ and default_broker_notifications
209
+ and default_backbroker_next
210
+ and single_default_datanotify
211
+ and not has_timers
212
+ and not has_timerscheat
213
+ and not cheat_on_open
214
+ and not has_stores
215
+ and not has_runwriters
216
+ and not broker_userhist
217
+ and not broker_fundhist
218
+ ):
219
+ if data0.notifs:
220
+ self._datanotify()
221
+ if self._event_stop:
222
+ return
223
+ quicknotify = self.p.quicknotify
224
+ strat_forward_line = single_runstrat._single_line_forward_line
225
+ strat_clock_datetime_line = single_runstrat._single_clock_datetime_line
226
+ strat_forward_append = strat_forward_line.array.append
227
+ strat_clock_datetime_array = strat_clock_datetime_line.array
228
+ strat_dlens = single_runstrat._dlens
229
+ strat_minperiod = single_runstrat._single_minperiod
230
+ strat_minperiod_len_line = single_runstrat._single_minperiod_len_line
231
+ strat_minperstatus = strat_minperiod - strat_minperiod_len_line.lencount
232
+ strat_orderspending = single_runstrat._orderspending
233
+ strat_tradespending = single_runstrat._tradespending
234
+ strat_dict = single_runstrat.__dict__
235
+ strat_next = single_runstrat.next
236
+ strat_nextstart = single_runstrat.nextstart
237
+ strat_prenext = single_runstrat.prenext
238
+ while True:
239
+ if not data0_direct_load():
240
+ break
241
+
242
+ if not (
243
+ broker._no_open_positions
244
+ and not broker_pending
245
+ and not broker_submitted
246
+ and not broker_toactivate
247
+ and not broker_cash_addition
248
+ and not broker_dual_side_mode
249
+ and not broker_notifications
250
+ ):
251
+ broker_next()
252
+
253
+ while broker_notifications:
254
+ order = broker_notifications.popleft()
255
+ owner = order.owner
256
+ if owner is None:
257
+ owner = single_runstrat
258
+ owner._addnotification(order, quicknotify=quicknotify)
259
+
260
+ if self._event_stop:
261
+ return
262
+
263
+ if strat_orderspending or strat_tradespending:
264
+ Strategy._next(single_runstrat)
265
+ strat_orderspending = single_runstrat._orderspending
266
+ strat_tradespending = single_runstrat._tradespending
267
+ strat_minperstatus = single_runstrat._minperstatus
268
+ else:
269
+ dt_value = strat_clock_datetime_array[strat_clock_datetime_line._idx]
270
+ strat_forward_line._idx += 1
271
+ strat_forward_line.lencount += 1
272
+ strat_forward_append(dt_value)
273
+ strat_dlens[0] = strat_clock_datetime_line.lencount
274
+
275
+ strat_minperstatus -= 1
276
+ strat_dict["_minperstatus"] = strat_minperstatus
277
+ if strat_minperstatus < 0:
278
+ strat_next()
279
+ elif strat_minperstatus == 0:
280
+ strat_nextstart()
281
+ else:
282
+ strat_prenext()
283
+ if self._event_stop:
284
+ return
285
+
286
+ if data0.notifs:
287
+ self._datanotify()
288
+ return
289
+ # Note: 'while True' (not 'while d0ret or d0ret is None') is intentional:
290
+ # when d0ret becomes False, the else branch still runs _last() on feeds
291
+ # and only breaks if no feed produces additional data.
292
+ while True:
293
+ # if any has live data in the buffer, no data will wait anything
294
+ # If any live data exists, newqcheck is False
295
+ if single_data:
296
+ newqcheck = True if single_default_haslivedata else not data0.haslivedata()
297
+ else:
298
+ newqcheck = not any(d.haslivedata() for d in datas)
299
+ # If live data exists
300
+ if not newqcheck:
301
+ # If no data has reached the live status or all, wait for
302
+ # the next incoming data
303
+ # livecount is the number of live data
304
+ if single_data:
305
+ livecount = data0._laststatus == data0.LIVE
306
+ else:
307
+ livecount = sum(d._laststatus == d.LIVE for d in datas)
308
+ # Override qcheck for mixed live/historical: wait only when
309
+ # no feeds are LIVE or ALL non-clone feeds are LIVE.
310
+ # When only some feeds are LIVE, skip wait for faster iteration.
311
+ newqcheck = not livecount or livecount == ldatas_noclones
312
+
313
+ lastret = False
314
+ # Notify anything from the store even before moving datas
315
+ # because datas may not move due to an error reported by the store
316
+ # Notify store related info
317
+ if has_stores:
318
+ self._storenotify()
319
+ if self._event_stop: # stop if requested
320
+ return
321
+ # Notify data related info
322
+ if not single_default_datanotify or data0.notifs:
323
+ self._datanotify()
324
+ if self._event_stop: # stop if requested
325
+ return
326
+
327
+ # record starting time and tell feeds to discount the elapsed time
328
+ # from the qcheck value
329
+ # Record start time and notify feed to subtract elapsed time from qcheck
330
+ if data0_direct_load is not None:
331
+ drets = (data0_direct_load(),)
332
+ else:
333
+ drets = []
334
+ if data0_direct_load is None and newqcheck and has_qcheck:
335
+ qstart = datetime.datetime.now(UTC)
336
+ for d in datas:
337
+ qlapse = datetime.datetime.now(UTC) - qstart
338
+ d.do_qcheck(newqcheck, qlapse.total_seconds())
339
+ d_next = d.next(ticks=False)
340
+ drets.append(d_next)
341
+ elif data0_direct_load is None:
342
+ for d in datas:
343
+ if has_qcheck:
344
+ d.do_qcheck(False, 0.0)
345
+ d_next = d.next(ticks=False)
346
+ drets.append(d_next)
347
+ # Iterate drets, if d0ret is False and any dret is None, d0ret is None
348
+ if single_data:
349
+ dret0 = drets[0]
350
+ d0ret = bool(dret0)
351
+ if not d0ret and dret0 is None:
352
+ d0ret = None
353
+ else:
354
+ d0ret = any(dret for dret in drets)
355
+ if not d0ret and any(dret is None for dret in drets):
356
+ d0ret = None
357
+ # If d0ret is not None
358
+ if d0ret:
359
+ # Get time
360
+ if single_data:
361
+ try:
362
+ data0_datetime_idx = data0_datetime_line._idx
363
+ if data0_datetime_idx >= 0:
364
+ dt0 = data0_datetime_line.array[data0_datetime_idx]
365
+ else:
366
+ dt0 = data0_datetime_line[0]
367
+ except (AttributeError, IndexError):
368
+ dt0 = data0.datetime[0]
369
+ dts = [dt0]
370
+ dmaster = data0
371
+ else:
372
+ dts = []
373
+ for i, ret in enumerate(drets):
374
+ dts.append(datas[i].datetime[0] if ret else None)
375
+ # Get index to minimum datetime
376
+ # Get minimum time
377
+ if onlyresample or noresample:
378
+ dt0 = min(d for d in dts if d is not None)
379
+ else:
380
+ dt0 = min(
381
+ (d for i, d in enumerate(dts) if d is not None and i not in rsonly)
382
+ )
383
+ # Get master data and time
384
+ dmaster = datas[dts.index(dt0)] # and timemaster
385
+ # Guard: dt0 < 1 means ordinal date before 0001-01-01
386
+ # (invalid/sentinel value from uninitialized data)
387
+ if dt0 < 1:
388
+ logger.warning(
389
+ "Invalid datetime value dt0=%s detected in _runnext, aborting run loop",
390
+ dt0,
391
+ )
392
+ return
393
+ if broker_userhist or broker_fundhist:
394
+ udtmaster = _num2date_cached(dt0)
395
+ self._udtmaster = udtmaster
396
+ self._dtmaster = (
397
+ udtmaster
398
+ if getattr(dmaster, "_tz", None) is None
399
+ else dmaster.num2date(dt0)
400
+ )
401
+
402
+ # Try to get something for those that didn't return
403
+ # Loop through drets
404
+ for i, ret in enumerate(drets):
405
+ # If ret is not None, continue to next ret
406
+ if ret: # dts already contains a valid datetime for this i
407
+ continue
408
+
409
+ # try to get data by checking with a master
410
+ # Get data and try to set time for dts
411
+ d = datas[i]
412
+ d._check(forcedata=dmaster) # check to force output
413
+ if d.next(datamaster=dmaster, ticks=False): # retry
414
+ dts[i] = d.datetime[0] # good -> store
415
+
416
+ # make sure only those at dmaster level end up delivering
417
+ # Iterate dts
418
+ for i, dti in enumerate(dts):
419
+ # If dti is not None
420
+ if dti is not None:
421
+ # Get data
422
+ di = datas[i]
423
+ if dti > dt0:
424
+ di.rewind() # cannot deliver yet
425
+ # If not replay
426
+ elif not di.replaying:
427
+ # Replay forces tick fill, else force here
428
+ try:
429
+ tick_direct_filled = di._tick_direct_filled
430
+ except AttributeError:
431
+ tick_direct_filled = False
432
+ if not tick_direct_filled:
433
+ di._tick_fill(force=True)
434
+ # If d0ret is None, iterate each data and call _check()
435
+ elif d0ret is None:
436
+ # meant for things like live feeds which may not produce a bar
437
+ # at the moment but need the loop to run for notifications and
438
+ # getting resample and others to produce timely bars
439
+ for data in datas:
440
+ data._check()
441
+ # If other case
442
+ else:
443
+ lastret = data0._last()
444
+ for data in datas1:
445
+ lastret += data._last(datamaster=data0)
446
+ if not lastret:
447
+ # Only go extra round if something was changed by "lasts"
448
+ break
449
+
450
+ # Datas may have generated a new notification after next
451
+ # Notify data info
452
+ if not single_default_datanotify or data0.notifs:
453
+ self._datanotify()
454
+ if self._event_stop: # stop if requested
455
+ return
456
+ # Check timer and iterate strategies, call _next_open() to run
457
+ if d0ret or lastret: # if any bar, check timers before broker
458
+ if has_timerscheat:
459
+ self._check_timers(runstrats, dt0, cheat=True)
460
+ if cheat_on_open:
461
+ if single_runstrat is not None:
462
+ single_runstrat_next_open()
463
+ if self._event_stop: # stop if requested
464
+ return
465
+ else:
466
+ for strat in runstrats:
467
+ strat._next_open()
468
+ if self._event_stop: # stop if requested
469
+ return
470
+ # Live brokers can receive fills during a gap in market bars.
471
+ # Bar-matching brokers still require populated data lines.
472
+ poll_without_bar = d0ret is None and broker_next_without_bar
473
+ if d0ret or lastret or poll_without_bar:
474
+ skip_broker_next = False
475
+ if default_backbroker_next:
476
+ skip_broker_next = (
477
+ broker._no_open_positions
478
+ and not broker_pending
479
+ and not broker_submitted
480
+ and not broker_toactivate
481
+ and not broker_userhist
482
+ and not broker_cash_addition
483
+ and not broker_fundhist
484
+ and not broker_dual_side_mode
485
+ and not broker_notifications
486
+ )
487
+ if not skip_broker_next:
488
+ broker_next()
489
+ if default_broker_notifications:
490
+ while broker_notifications:
491
+ order = broker_notifications.popleft()
492
+ owner = order.owner
493
+ if owner is None:
494
+ owner = self.runningstrats[0] # default
495
+ owner._addnotification(order, quicknotify=self.p.quicknotify)
496
+ else:
497
+ while True:
498
+ order = broker_get_notification()
499
+ if order is None:
500
+ break
501
+ owner = order.owner
502
+ if owner is None:
503
+ owner = self.runningstrats[0] # default
504
+ owner._addnotification(order, quicknotify=self.p.quicknotify)
505
+ if poll_without_bar:
506
+ for strat in runstrats:
507
+ if not self.p.quicknotify:
508
+ strat._notify()
509
+ strat.clear()
510
+ if self._event_stop: # stop if requested
511
+ return
512
+
513
+ if d0ret is None:
514
+ for notify_idle in idle_notifiers:
515
+ notify_idle()
516
+ if self._event_stop:
517
+ return
518
+
519
+ # Notify timer and iterate strategies to run
520
+ if d0ret or lastret: # bars produced by data or filters
521
+ if has_timers:
522
+ self._check_timers(runstrats, dt0, cheat=False)
523
+ if single_runstrat is not None:
524
+ single_runstrat_next()
525
+ if self._event_stop: # stop if requested
526
+ return
527
+
528
+ if has_runwriters:
529
+ self._next_writers(runstrats)
530
+ else:
531
+ for strat in runstrats:
532
+ strat._next()
533
+ if self._event_stop: # stop if requested
534
+ return
535
+
536
+ if has_runwriters:
537
+ self._next_writers(runstrats)
538
+ # Last notification chance before stopping
539
+ # Notify data info
540
+ if not single_default_datanotify or data0.notifs:
541
+ self._datanotify()
542
+ if self._event_stop: # stop if requested
543
+ return
544
+ # Notify store info
545
+ if has_stores:
546
+ self._storenotify()
547
+ if self._event_stop: # stop if requested
548
+ return
549
+ except Exception:
550
+ logger.exception("Unhandled exception in _runnext")
551
+ raise
@@ -0,0 +1,142 @@
1
+ """Cerebro vectorized engine mixin (iteration 28 split).
2
+
3
+ Moved verbatim from ``backtrader/cerebro.py``: ``_runonce`` (modern) and
4
+ ``_runonce_old`` (oldsync).
5
+ """
6
+
7
+ from ..feed import AbstractDataBase
8
+
9
+
10
+ class RunOnceMixin:
11
+ """Vectorized engine half of Cerebro (see module docstring)."""
12
+
13
+ # Old runonce method, similar to runonce
14
+ def _runonce_old(self, runstrats):
15
+ """
16
+ Actual implementation of run in vector mode.
17
+ Strategies are still invoked on a pseudo-event mode in which `next`
18
+ is called for each data arrival
19
+ """
20
+
21
+ for strat in runstrats:
22
+ strat._once()
23
+
24
+ # The default once for strategies does nothing and therefore
25
+ # has not moved forward all datas/indicators/observers that
26
+ # were homed before calling once, Hence no "need" to do it
27
+ # here again, because pointers are at 0
28
+ data0 = self.datas[0]
29
+ datas = self.datas[1:]
30
+ for i in range(data0.buflen()):
31
+ self._storenotify()
32
+ if self._event_stop: # stop if requested
33
+ return
34
+ self._datanotify()
35
+ if self._event_stop: # stop if requested
36
+ return
37
+
38
+ data0.advance()
39
+ for data in datas:
40
+ data.advance(datamaster=data0)
41
+
42
+ self._brokernotify()
43
+ if self._event_stop: # stop if requested
44
+ return
45
+
46
+ for strat in runstrats:
47
+ # data0.datetime[0] for compat. w/ new strategy's oncepost
48
+ strat._oncepost(data0.datetime[0])
49
+ if self._event_stop: # stop if requested
50
+ return
51
+
52
+ self._next_writers(runstrats)
53
+
54
+ self._datanotify()
55
+ if self._event_stop: # stop if requested
56
+ return
57
+ self._storenotify()
58
+ if self._event_stop: # stop if requested
59
+ return
60
+
61
+ # runonce
62
+ def _runonce(self, runstrats):
63
+ """
64
+ Actual implementation of run in vector mode.
65
+
66
+ Strategies are still invoked on a pseudo-event mode in which `next`
67
+ is called for each data arrival
68
+ """
69
+ # Iterate strategies, call _once and reset
70
+ for strat in runstrats:
71
+ strat._once()
72
+ strat.reset() # strat called next by next - reset lines
73
+
74
+ # The default once for strategies does nothing and therefore
75
+ # has not moved forward all datas/indicators/observers that
76
+ # were homed before calling once, Hence no "need" to do it
77
+ # here again, because pointers are at 0
78
+ # Sort data from small period to large period
79
+ datas = sorted(self.datas, key=lambda x: (x._timeframe, x._compression))
80
+ data0 = datas[0]
81
+ single_data = len(datas) == 1
82
+ single_default_datanotify = (
83
+ single_data and type(data0).get_notifications is AbstractDataBase.get_notifications
84
+ )
85
+ cheat_on_open = self.p.cheat_on_open
86
+ has_timers = bool(self._timers)
87
+ has_timerscheat = bool(self._timerscheat)
88
+ has_stores = bool(self.stores)
89
+ has_runwriters = bool(self.runwriters)
90
+
91
+ while True:
92
+ if has_stores:
93
+ self._storenotify()
94
+ if self._event_stop: # stop if requested
95
+ return
96
+ if not single_default_datanotify or data0.notifs:
97
+ self._datanotify()
98
+ if self._event_stop: # stop if requested
99
+ return
100
+
101
+ # Check the next incoming date in the datas
102
+ # For each data call advance_peek(), get minimum time as the first one
103
+ dts = [d.advance_peek() for d in datas]
104
+ dt0 = min(dts)
105
+ if dt0 == float("inf"):
106
+ break # no data delivers anything
107
+
108
+ # Timemaster if needed be
109
+ # dmaster = datas[dts.index(dt0)] # and timemaster
110
+ # For each data time, if time <= minimum time, advance data, otherwise ignore
111
+ for i, dti in enumerate(dts):
112
+ if dti <= dt0:
113
+ datas[i].advance()
114
+ # self._plotfillers2[i].append(slen) # mark as fill
115
+ else:
116
+ # self._plotfillers[i].append(slen)
117
+ pass
118
+ # Check timer
119
+ if has_timerscheat:
120
+ self._check_timers(runstrats, dt0, cheat=True)
121
+ # If cheat_on_open, call _oncepost_open() for each strategy
122
+ if cheat_on_open:
123
+ for strat in runstrats:
124
+ strat._oncepost_open()
125
+ # If stop was called, stop
126
+ if self._event_stop: # stop if requested
127
+ return
128
+ # Call _brokernotify()
129
+ self._brokernotify()
130
+ # If stop was called, stop
131
+ if self._event_stop: # stop if requested
132
+ return
133
+ # Check timer
134
+ if has_timers:
135
+ self._check_timers(runstrats, dt0, cheat=False)
136
+
137
+ for strat in runstrats:
138
+ strat._oncepost(dt0)
139
+ if self._event_stop: # stop if requested
140
+ return
141
+ if has_runwriters:
142
+ self._next_writers(runstrats)