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,1001 @@
1
+ #!/usr/bin/env python
2
+ """Resampler and Filter Module - Data resampling and replay functionality.
3
+
4
+ This module provides classes for resampling data to different timeframes
5
+ and replaying data at compressed timeframes. It includes the base
6
+ resampler and replayer classes along with specific implementations for
7
+ different time periods.
8
+
9
+ Key Classes:
10
+ Resampler: Base class for resampling data to different timeframes.
11
+ Replayer: Base class for replaying data with session information.
12
+ DTFaker: Provides fake datetime for live/real-time data feeds.
13
+
14
+ Example:
15
+ Resampling daily data to weekly:
16
+ >>> data = bt.feeds.GenericCSVData(dataname='daily.csv')
17
+ >>> cerebro.adddata(data)
18
+ >>> cerebro.resampledata(data, timeframe=bt.TimeFrame.Weeks)
19
+ """
20
+
21
+ from datetime import datetime, timedelta, timezone
22
+
23
+ from .dataseries import TimeFrame, _Bar
24
+ from .parameters import ParameterizedBase
25
+ from .utils.date import date2num, num2date
26
+
27
+ # Python 3.11+ has datetime.UTC, earlier versions use timezone.utc
28
+ UTC = timezone.utc
29
+
30
+
31
+ # This class is only used in the _checkbarover function
32
+ # chkdata = DTFaker(data, forcedata) if fromcheck else data
33
+ class DTFaker:
34
+ """Provides fake datetime for data sources that need periodic checks.
35
+
36
+ This class is used for real-time data feeds that return None from _load
37
+ to indicate that a check of the resampler and/or notification queue
38
+ is needed. It provides the current time in both UTC and localized formats.
39
+
40
+ Attributes:
41
+ data: The underlying data source.
42
+ _dt: UTC-like time as numeric value.
43
+ _dtime: Localized datetime.
44
+ sessionend: Trading day end time.
45
+
46
+ Example:
47
+ >>> faker = DTFaker(data)
48
+ >>> print(faker.datetime()) # Current localized time
49
+ """
50
+
51
+ # This will only be used for data sources which at some point in time
52
+ # return None from _load to indicate that a check of the resampler and/or
53
+ # notification queue is needed
54
+ # This is meant (at least initially) for real-time feeds, because those are
55
+ # the ones in need of events like the ones described above.
56
+ # These data sources should also be producing ``utc`` time directly because
57
+ # the real-time feed is (more often than not) timestamped and utc provides
58
+ # a universal reference,
59
+ # That's why below the timestamp is chosen in UTC and passed directly to
60
+ # date2num to avoid localization.But it is extracted from data.num2date
61
+ # to ensure the returned datetime object is localized according to the
62
+ # expected output by the user (local timezone or any specified)
63
+
64
+ # Initialize
65
+ def __init__(self, data, forcedata=None):
66
+ """Initialize the DTFaker with current time.
67
+
68
+ Args:
69
+ data: The underlying data source.
70
+ forcedata: Optional data source to force time from.
71
+ """
72
+ # Data
73
+ self.data = data
74
+
75
+ # Aliases
76
+ self.datetime = self
77
+ self.p = self
78
+
79
+ # If forcedata is None
80
+ if forcedata is None:
81
+ # Get current utc time and add data time offset
82
+ _dtime = datetime.now(UTC) + data._timeoffset()
83
+ # Convert calculated utc time to number
84
+ self._dt = dt = date2num(_dtime) # utc-like time
85
+ # Convert numeric time to localized time format
86
+ self._dtime = data.num2date(dt) # localized time
87
+ # If forcedata is not None
88
+ else:
89
+ # Get corresponding time from forcedata's datetime column as utc time
90
+ self._dt = forcedata.datetime[0] # utc-like time
91
+ # Get local time directly from forcedata
92
+ self._dtime = forcedata.datetime.datetime() # localized time
93
+ # Trading day end time
94
+ self.sessionend = data.p.sessionend
95
+
96
+ # Length
97
+ def __len__(self):
98
+ return len(self.data)
99
+
100
+ # Return localized date and time when called
101
+ def __call__(self, idx=0):
102
+ """Return the localized datetime.
103
+
104
+ Args:
105
+ idx: Index (ignored, for compatibility).
106
+
107
+ Returns:
108
+ Localized datetime object.
109
+ """
110
+ return self._dtime # simulates data.datetime.datetime()
111
+
112
+ # datetime returns localized date and time
113
+ def datetime(self, idx=0):
114
+ """Return the localized datetime.
115
+
116
+ Args:
117
+ idx: Index (ignored, for compatibility).
118
+
119
+ Returns:
120
+ Localized datetime object.
121
+ """
122
+ return self._dtime
123
+
124
+ # Return localized date
125
+ def date(self, idx=0):
126
+ """Return the localized date.
127
+
128
+ Args:
129
+ idx: Index (ignored, for compatibility).
130
+
131
+ Returns:
132
+ Date object.
133
+ """
134
+ return self._dtime.date()
135
+
136
+ # Return localized time
137
+ def time(self, idx=0):
138
+ """Return the localized time.
139
+
140
+ Args:
141
+ idx: Index (ignored, for compatibility).
142
+
143
+ Returns:
144
+ Time object.
145
+ """
146
+ return self._dtime.time()
147
+
148
+ # Return data calendar
149
+ @property
150
+ def _calendar(self):
151
+ return self.data._calendar
152
+
153
+ # If idx=0, return utc numeric time, otherwise return -inf
154
+ def __getitem__(self, idx):
155
+ return self._dt if idx == 0 else float("-inf")
156
+
157
+ # Convert number to date and time
158
+ def num2date(self, *args, **kwargs):
159
+ """Convert numeric time to datetime.
160
+
161
+ Delegates to the underlying data source's num2date method.
162
+
163
+ Returns:
164
+ Datetime object.
165
+ """
166
+ return self.data.num2date(*args, **kwargs)
167
+
168
+ # Convert date and time to number
169
+ def date2num(self, *args, **kwargs):
170
+ """Convert datetime to numeric time.
171
+
172
+ Delegates to the underlying data source's date2num method.
173
+
174
+ Returns:
175
+ Float representing the datetime.
176
+ """
177
+ return self.data.date2num(*args, **kwargs)
178
+
179
+ # Get trading day end time
180
+ def _getnexteos(self):
181
+ return self.data._getnexteos()
182
+
183
+
184
+ # Base class for resampler
185
+ class _BaseResampler(ParameterizedBase):
186
+ # Parameters
187
+ params = (
188
+ ("bar2edge", True),
189
+ ("adjbartime", True),
190
+ ("rightedge", True),
191
+ ("boundoff", 0),
192
+ ("timeframe", TimeFrame.Days),
193
+ ("compression", 1),
194
+ ("takelate", True),
195
+ ("sessionend", True),
196
+ )
197
+
198
+ # Initialize
199
+ def __init__(self, data, **kwargs):
200
+ """Initialize the base resampler.
201
+
202
+ Sets up the resampling configuration based on timeframe and
203
+ compression parameters, and modifies the data source accordingly.
204
+
205
+ Args:
206
+ data: The data source to resample.
207
+ **kwargs: Additional parameters for the resampler.
208
+ """
209
+ super().__init__(**kwargs)
210
+ # If timeframe is less than day but greater than tick, subdays is True, subdays represents intraday timeframe
211
+ self.subdays = TimeFrame.Ticks < self.p.timeframe < TimeFrame.Days
212
+ # If timeframe is less than week, subweeks is True
213
+ self.subweeks = self.p.timeframe < TimeFrame.Weeks
214
+ # If not subdays, and data timeframe equals parameter timeframe, and parameter compression divided by data compression remainder is 0, componly is True
215
+ self._source_timeframe = data._timeframe
216
+ self._source_compression = data._compression
217
+ self.componly = (
218
+ not self.subdays
219
+ and data._timeframe == self.p.timeframe
220
+ and not (self.p.compression % data._compression)
221
+ )
222
+ # Create an object to save bar data
223
+ self.bar = _Bar(maxdate=True) # bar holder
224
+ # Number of bars produced, used to control compression count
225
+ self.compcount = 0 # count of produced bars to control compression
226
+ # Whether it is the first bar
227
+ self._firstbar = True
228
+ # If bar2edge, adjbartime, subweeks are all True, doadjusttime is True
229
+ self.doadjusttime = self.p.bar2edge and self.p.adjbartime and self.subweeks
230
+ # The end time of this trading day
231
+ self._nexteos = None
232
+
233
+ # Modify data information according to own parameters
234
+ # During initialization, modify data attributes based on parameters
235
+ # Data resampling is 1
236
+ data.resampling = 1
237
+ # replaying equals replaying
238
+ data.replaying = self.replaying
239
+ # Data timeframe equals parameter timeframe
240
+ data._timeframe = self.p.timeframe
241
+ # Data compression equals parameter compression
242
+ data._compression = self.p.compression
243
+
244
+ self.data = data
245
+
246
+ # How to handle late-arriving data, if not subdays return False, if data length > 1 and current time <= previous time return True
247
+ def _latedata(self, data):
248
+ # new data at position 0, still untouched from stream
249
+ if not self.subdays:
250
+ return False
251
+
252
+ # Time already delivered
253
+ return len(data) > 1 and data.datetime[0] <= data.datetime[-1]
254
+
255
+ # Whether to check if bar is over
256
+ def _checkbarover(self, data, fromcheck=False, forcedata=None):
257
+ # Data to check, if fromcheck is True, use DTFaker to generate instance, otherwise use data
258
+ chkdata = DTFaker(data, forcedata) if fromcheck else data
259
+ # Whether finished
260
+ isover = False
261
+ # If not componly and _barover(chkdata) is False, return False
262
+ if not self.componly and not self._barover(chkdata):
263
+ return isover
264
+ # If intraday and bar2edge is True, return True
265
+ if self.subdays and self.p.bar2edge:
266
+ isover = True
267
+ # If fromcheck is False
268
+ elif not fromcheck: # fromcheck doesn't increase compcount
269
+ # compcount+1
270
+ self.compcount += 1
271
+ # If compcount divided by compression equals 0, return True
272
+ if not (self.compcount % self.p.compression):
273
+ # boundary crossed and enough bars for compression ... proceed
274
+ isover = True
275
+
276
+ return isover
277
+
278
+ # Determine if data has finished
279
+ def _barover(self, data):
280
+ # Timeframe
281
+ tframe = self.p.timeframe
282
+ # If timeframe equals tick, return bar.isopen()
283
+ if tframe == TimeFrame.Ticks:
284
+ # Ticks is already the lowest level
285
+ return self.bar.isopen()
286
+ # If timeframe is less than day, call _barover_subdays(data)
287
+ if tframe < TimeFrame.Days:
288
+ return self._barover_subdays(data)
289
+ # If timeframe equals day, call _barover_days(data)
290
+ if tframe == TimeFrame.Days:
291
+ return self._barover_days(data)
292
+ # If timeframe equals week, call _barover_weeks(data)
293
+ if tframe == TimeFrame.Weeks:
294
+ return self._barover_weeks(data)
295
+ # If timeframe equals month, call _barover_months(data)
296
+ if tframe == TimeFrame.Months:
297
+ return self._barover_months(data)
298
+ # If timeframe equals year, call _barover_years(data)
299
+ if tframe == TimeFrame.Years:
300
+ return self._barover_years(data)
301
+
302
+ # Set session end time
303
+ def _eosset(self):
304
+ if self._nexteos is None:
305
+ self._nexteos, self._nextdteos = self.data._getnexteos()
306
+ return
307
+
308
+ # Check session end time
309
+ def _eoscheck(self, data, seteos=True, exact=False):
310
+ # If seteos is True, directly call _eosset to calculate session end time
311
+ if seteos:
312
+ self._eosset()
313
+ # Compare current data time with session end time
314
+ equal = data.datetime[0] == self._nextdteos
315
+ grter = data.datetime[0] > self._nextdteos
316
+ # If exact is True, ret equals equal,
317
+ # Otherwise, if grter is True, if bar.isopen() is True and bar.datetime < next end time, ret equals True
318
+ # Otherwise, ret equals equal
319
+ if exact:
320
+ ret = equal
321
+ else:
322
+ # if the compared data goes over the endofsession
323
+ # make sure the resampled bar is open and has something before that
324
+ # end of the session, It could be a weekend and nothing was delivered
325
+ # until Monday
326
+ if grter:
327
+ ret = self.bar.isopen() and self.bar.datetime <= self._nextdteos
328
+ else:
329
+ ret = equal
330
+ # If ret is True, _lasteos equals _nexteos, _lastdteos equals _nextdteos
331
+ # And set _nexteos and _nextdteos to None and -inf respectively
332
+ if ret:
333
+ self._lasteos = self._nexteos
334
+ self._lastdteos = self._nextdteos
335
+ self._nexteos = None
336
+ self._nextdteos = float("-inf")
337
+
338
+ return ret
339
+
340
+ # Check days
341
+ def _barover_days(self, data):
342
+ return self._eoscheck(data)
343
+
344
+ # Check weeks
345
+ def _barover_weeks(self, data):
346
+ # If data's _calendar is None
347
+ if self.data._calendar is None:
348
+ # Get specific year, week number and day from date
349
+ year, week, _ = data.num2date(self.bar.datetime).date().isocalendar()
350
+ # Get bar's week number
351
+ yearweek = year * 100 + week
352
+ # Get data's year, week number and day, and get data's week number
353
+ baryear, barweek, _ = data.datetime.date().isocalendar()
354
+ bar_yearweek = baryear * 100 + barweek
355
+ # If data's week number is greater than bar's week number, return True, otherwise return False
356
+ return bar_yearweek > yearweek
357
+ # If data's _calendar is not None, call last_weekday
358
+ return data._calendar.last_weekday(data.datetime.date())
359
+
360
+ # Check months
361
+ def _barover_months(self, data):
362
+ dt = data.num2date(self.bar.datetime).date()
363
+ yearmonth = dt.year * 100 + dt.month
364
+
365
+ bardt = data.datetime.datetime()
366
+ bar_yearmonth = bardt.year * 100 + bardt.month
367
+
368
+ return bar_yearmonth > yearmonth
369
+
370
+ # Check years
371
+ def _barover_years(self, data):
372
+ return data.datetime.datetime().year > data.num2date(self.bar.datetime).year
373
+
374
+ # Get time point
375
+ def _gettmpoint(self, tm):
376
+ """
377
+ Returns the point of time intraday for a given time according to the
378
+ timeframe
379
+
380
+ - Ex 1: 00:05:00 in minutes -> point = 5
381
+ - Ex 2: 00:05:20 in seconds -> point = 5 * 60 + 20 = 320
382
+ """
383
+ # Minute point
384
+ point = tm.hour * 60 + tm.minute
385
+ # Remaining point
386
+ restpoint = 0
387
+ # If timeframe is less than minutes
388
+ if self.p.timeframe < TimeFrame.Minutes:
389
+ # Second point
390
+ point = point * 60 + tm.second
391
+ # If timeframe is less than seconds
392
+ if self.p.timeframe < TimeFrame.Seconds:
393
+ # Convert point to microseconds
394
+ point = point * 1e6 + tm.microsecond
395
+ # If timeframe is not less than seconds, remaining point is microseconds
396
+ else:
397
+ restpoint = tm.microsecond
398
+ # If timeframe is not less than minutes, remaining point is seconds and microseconds
399
+ else:
400
+ restpoint = tm.second + tm.microsecond
401
+ # Add boundoff to point
402
+ point += self.p.boundoff
403
+
404
+ return point, restpoint
405
+
406
+ # Intraday bar over
407
+ def _barover_subdays(self, data):
408
+ # If _eoscheck(data) returns True, then function returns True
409
+ if self._eoscheck(data):
410
+ return True
411
+ # If data time is less than bar time, return False
412
+ if data.datetime[0] < self.bar.datetime:
413
+ return False
414
+
415
+ # Get time objects for the comparisons - in utc-like format
416
+ # Get bar and data time
417
+ tm = num2date(self.bar.datetime).time()
418
+ bartm = num2date(data.datetime[0]).time()
419
+ # Get self.bar's time point and data's time point respectively
420
+ point, _ = self._gettmpoint(tm)
421
+ barpoint, _ = self._gettmpoint(bartm)
422
+ # Set ret to False
423
+ ret = False
424
+ # If data's time point is less than bar's time point, return False
425
+ # If data's time point is greater than bar's time point, further analyze
426
+ if barpoint > point:
427
+ # The data bar has surpassed the internal bar
428
+ # If bar2edge is False, return True
429
+ if not self.p.bar2edge:
430
+ # Compression done on a simple bar basis (like days)
431
+ ret = True
432
+ # If compression is 1, return True
433
+ elif self.p.compression == 1:
434
+ # no bar compression requested -> internal bar done
435
+ ret = True
436
+ # If bar2edge is True and compression is not 1, calculate remainder of dividing points by compression
437
+ # If data's point remainder is greater than bar's point remainder, return True
438
+ else:
439
+ point_comp = point // self.p.compression
440
+ barpoint_comp = barpoint // self.p.compression
441
+
442
+ # Went over boundary including compression
443
+ if barpoint_comp > point_comp:
444
+ ret = True
445
+
446
+ return ret
447
+
448
+ # Check whether to submit currently stored bar when data hasn't moved forward
449
+ def check(self, data, _forcedata=None):
450
+ """Called to check if the current stored bar has to be delivered in
451
+ spite of the data not having moved forward. If no ticks from a live
452
+ feed come in, a 5-second resampled bar could be delivered 20 seconds
453
+ later. When this method is called the wall clock (incl data time
454
+ offset) is called to check if the time has gone so far as to have to
455
+ deliver the already stored data
456
+ """
457
+ if not self.bar.isopen():
458
+ return None
459
+
460
+ return self(data, fromcheck=True, forcedata=_forcedata)
461
+
462
+ # Determine if data is about to form a bar
463
+ def _dataonedge(self, data):
464
+ # If subweek is False, if data._calendar is None, return False and True
465
+ if not self.subweeks:
466
+ if data._calendar is None:
467
+ return False, True # nothing can be done
468
+ # Timeframe
469
+ tframe = self.p.timeframe
470
+ # Set ret to False
471
+ ret = False
472
+ # If timeframe equals week, call last_weekday to check
473
+ # If timeframe equals month, call last_monthday to check
474
+ # If timeframe equals year, call last_yearday to check
475
+ if tframe == TimeFrame.Weeks: # Ticks is already the lowest
476
+ ret = data._calendar.last_weekday(data.datetime.date())
477
+ elif tframe == TimeFrame.Months:
478
+ ret = data._calendar.last_monthday(data.datetime.date())
479
+ elif tframe == TimeFrame.Years:
480
+ ret = data._calendar.last_yearday(data.datetime.date())
481
+ # If ret is True
482
+ if ret:
483
+ # Data must be consumed but compression may not be met yet
484
+ # Prevent barcheckover from being called because it could again
485
+ # increase compcount
486
+ # Set docheckover to False
487
+ docheckover = False
488
+ # compcount+1
489
+ self.compcount += 1
490
+ # If compcount divided by compression remainder equals 0, return True, otherwise return False
491
+ ret = not (self.compcount % self.p.compression)
492
+ # If ret equals False, docheckover equals True
493
+ else:
494
+ docheckover = True
495
+ # Return ret, docheckover
496
+ return ret, docheckover
497
+ # _eoscheck check, return two True
498
+ if self._eoscheck(data, exact=True):
499
+ return True, True
500
+ # If intraday
501
+ if self.subdays:
502
+ # Get data's point and remaining point
503
+ point, prest = self._gettmpoint(data.datetime.time())
504
+ # If remaining point is not 0, return False and True
505
+ if prest:
506
+ return False, True # cannot be on boundary, subunits present
507
+
508
+ # Pass through compression to get boundary and rest over boundary
509
+ # Calculate boundary and remaining boundary
510
+ bound, brest = divmod(point, self.p.compression)
511
+
512
+ # if no extra and decomp bound is point
513
+ # If divmod result remainder is 0, return two True
514
+ return brest == 0 and point == (bound * self.p.compression), True
515
+
516
+ # Code overriden by eoscheck
517
+ # This code will not run
518
+ if False and self.p.sessionend: # noqa: SIM223 # intentionally dead code
519
+ # Days scenario - get datetime to compare in output timezone
520
+ # because p.sessionend is expected in output timezone
521
+ bdtime = data.datetime.datetime()
522
+ bsend = datetime.combine(bdtime.date(), data.p.sessionend)
523
+ return bdtime == bsend
524
+ # If none of above reached return, return False, True
525
+ return False, True # subweeks, not subdays and not sessionend
526
+
527
+ # Calculate adjusted time
528
+ def _calcadjtime(self, greater=False):
529
+ if self._nexteos is None:
530
+ # Session has been exceeded - end of session is the mark
531
+ return self._lastdteos # utc-like
532
+
533
+ dt = self.data.num2date(self.bar.datetime)
534
+
535
+ # Get current time
536
+ tm = dt.time()
537
+ # Get the point of the day in the time frame unit (ex: minute 200)
538
+ point, _ = self._gettmpoint(tm)
539
+
540
+ # Apply compression to update the point position (comp 5 -> 200 // 5)
541
+ # point = (point // self.p.compression)
542
+ point = point // self.p.compression
543
+
544
+ # If rightedge (end of boundary is activated) add it unless recursing
545
+ point += self.p.rightedge
546
+
547
+ # Restore point to the timeframe units by de-applying compression
548
+ point *= self.p.compression
549
+
550
+ # Get hours, minutes, seconds and microseconds
551
+ extradays = 0
552
+ if self.p.timeframe == TimeFrame.Minutes:
553
+ ph, pm = divmod(point, 60)
554
+ ps = 0
555
+ pus = 0
556
+ elif self.p.timeframe == TimeFrame.Seconds:
557
+ ph, pm = divmod(point, 60 * 60)
558
+ pm, ps = divmod(pm, 60)
559
+ pus = 0
560
+ elif self.p.timeframe <= TimeFrame.MicroSeconds:
561
+ ph, pm = divmod(point, 60 * 60 * 1e6)
562
+ pm, psec = divmod(pm, 60 * 1e6)
563
+ ps, pus = divmod(psec, 1e6)
564
+ elif self.p.timeframe == TimeFrame.Days:
565
+ # last resort
566
+ eost = self._nexteos.time()
567
+ ph = eost.hour
568
+ pm = eost.minute
569
+ ps = eost.second
570
+ pus = eost.microsecond
571
+
572
+ if ph > 23: # went over midnight:
573
+ extradays = ph // 24
574
+ ph %= 24
575
+
576
+ # Replace intraday parts with the calculated ones and update it
577
+ dt = dt.replace(hour=int(ph), minute=int(pm), second=int(ps), microsecond=int(pus))
578
+ if extradays:
579
+ dt += timedelta(days=extradays)
580
+ dtnum = self.data.date2num(dt)
581
+ return dtnum
582
+
583
+ # Adjust bar time
584
+ def _adjusttime(self, greater=False, forcedata=None):
585
+ """
586
+ Adjusts the time of calculated bar (from the underlying data source) by
587
+ using the timeframe to the appropriate boundary, with compression taken
588
+ into account
589
+
590
+ Depending on param ``rightedge`` uses the starting boundary or the
591
+ ending one
592
+ """
593
+
594
+ dtnum = self._calcadjtime(greater=greater)
595
+ if greater and dtnum <= self.bar.datetime:
596
+ return False
597
+
598
+ self.bar.datetime = dtnum
599
+ return True
600
+
601
+
602
+ # Resample small period data to form large period data
603
+ class Resampler(_BaseResampler):
604
+ """This class resamples data of a given timeframe to a larger timeframe.
605
+
606
+ Params
607
+
608
+ - Bar2edge (default: True)
609
+
610
+ Resamples using time boundaries as the target.For example, with a
611
+ "ticks -> 5 seconds" the resulting 5-seconds bars will be aligned to
612
+ xx:00, xx:05, xx:10 ...
613
+
614
+ # When resampling, use time boundary as target, for example if ticks data wants to resample to 5 seconds, bars will be formed at xx:00, xx:05, xx:10
615
+
616
+ - Adjbartime (default: True)
617
+
618
+ Use the time at the boundary to adjust the time of the delivered
619
+ resampled bar instead of the last seen timestamp. If resampling to "5
620
+ seconds" the time of the bar will be adjusted, for example, to hh:mm:05
621
+ even if the last seen timestamp was hh:mm:04.33
622
+
623
+ :note::
624
+
625
+ Time will only be adjusted if "bar2edge" is True. It wouldn't make
626
+ sense to adjust the time if the bar has not been aligned to a
627
+ boundary
628
+ # Adjust the last bar's final time, when bar2edge is True, use the final boundary as the last bar's time
629
+
630
+ - Rightedge (default: True)
631
+
632
+ Use the right edge of the time boundaries to set the time.
633
+
634
+ If False and compressing to 5 seconds, the time of a resampled bar for
635
+ seconds between hh:mm:00 and hh:mm:04 will be hh:mm:00 (the starting
636
+ boundary
637
+
638
+ If True, the used boundary for the time will be hh:mm:05 (the ending
639
+ boundary)
640
+ # Whether to use the right time boundary, for example if time boundary is hh:mm:00:hh:mm:05, if set to True, will use hh:mm:05
641
+ # Set to False, will use hh:mm:00
642
+ """
643
+
644
+ # Parameters
645
+ params = (
646
+ ("bar2edge", True),
647
+ ("adjbartime", True),
648
+ ("rightedge", True),
649
+ )
650
+
651
+ replaying = False
652
+
653
+ def _last_bar_complete(self):
654
+ if self.p.timeframe != TimeFrame.Days or self._source_timeframe >= TimeFrame.Days:
655
+ return True
656
+
657
+ if self._nexteos is None:
658
+ self._eosset()
659
+
660
+ return self.bar.datetime + self._source_bar_duration() + 1e-9 >= self._nextdteos
661
+
662
+ def _source_bar_duration(self):
663
+ if self._source_timeframe == TimeFrame.MicroSeconds:
664
+ return self._source_compression / 86400000000.0
665
+ if self._source_timeframe == TimeFrame.Seconds:
666
+ return self._source_compression / 86400.0
667
+ if self._source_timeframe == TimeFrame.Minutes:
668
+ return self._source_compression / 1440.0
669
+ return 0.0
670
+
671
+ # Called when data no longer produces bars, can be called multiple times, has chance to produce extra bars when must deliver bar
672
+ def last(self, data):
673
+ """Called when the data is no longer producing bars
674
+
675
+ Can be called multiple times. It has the chance to (for example)
676
+ produce extra bars which may still be accumulated and have to be
677
+ delivered
678
+ """
679
+ if self.bar.isopen():
680
+ if not self._last_bar_complete():
681
+ return False
682
+
683
+ if self.doadjusttime:
684
+ self._adjusttime()
685
+
686
+ data._add2stack(self.bar.lvalues())
687
+ self.bar.bstart(maxdate=True) # close the bar to avoid dups
688
+ return True
689
+
690
+ return False
691
+
692
+ # Used when calling resampler
693
+ def __call__(self, data, fromcheck=False, forcedata=None):
694
+ """Called for each set of values produced by the data source"""
695
+ consumed = False
696
+ onedge = False
697
+ docheckover = True
698
+ if not fromcheck:
699
+ if self._latedata(data):
700
+ if not self.p.takelate:
701
+ data.backwards()
702
+ return True # get a new bar
703
+
704
+ self.bar.bupdate(data) # update new or existing bar
705
+ # push time beyond reference
706
+ self.bar.datetime = data.datetime[-1] + 0.000001
707
+ data.backwards() # remove used bar
708
+ return True
709
+
710
+ if self.componly: # only if not subdays
711
+ # Get a session ref before rewinding
712
+ _, self._lastdteos = self.data._getnexteos()
713
+ consumed = True
714
+
715
+ else:
716
+ onedge, docheckover = self._dataonedge(data) # for subdays
717
+ consumed = onedge
718
+
719
+ if consumed:
720
+ self.bar.bupdate(data) # update new or existing bar
721
+ data.backwards() # remove used bar
722
+
723
+ # if self.bar.isopen and (onedge or (docheckover and checkbarover))
724
+ cond = self.bar.isopen()
725
+ if cond: # original is and, the 2nd term must also be true
726
+ if not onedge: # onedge true is sufficient
727
+ if docheckover:
728
+ cond = self._checkbarover(data, fromcheck=fromcheck, forcedata=forcedata)
729
+ if cond:
730
+ dodeliver = False
731
+ if forcedata is not None:
732
+ # check our delivery time is not larger than that of forcedata
733
+ tframe = self.p.timeframe
734
+ if tframe == TimeFrame.Ticks: # Ticks is already the lowest
735
+ dodeliver = True
736
+ elif tframe == TimeFrame.Minutes or tframe == TimeFrame.Days:
737
+ dtnum = self._calcadjtime(greater=True)
738
+ dodeliver = dtnum <= forcedata.datetime[0]
739
+ else:
740
+ dodeliver = True
741
+
742
+ if dodeliver:
743
+ if not onedge and self.doadjusttime:
744
+ self._adjusttime(greater=True, forcedata=forcedata)
745
+
746
+ data._add2stack(self.bar.lvalues())
747
+ self.bar.bstart(maxdate=True) # bar delivered -> restart
748
+
749
+ if not fromcheck:
750
+ if not consumed:
751
+ self.bar.bupdate(data) # update new or existing bar
752
+ data.backwards() # remove used bar
753
+
754
+ return True
755
+
756
+
757
+ # Replayer class
758
+ class Replayer(_BaseResampler):
759
+ """This class replays data of a given timeframe to a larger timeframe.
760
+
761
+ It simulates the action of the market by slowly building up (for ex.) a
762
+ daily bar from tick/seconds/minutes data
763
+
764
+ Only when the bar is complete will the "length" of the data be changed
765
+ effectively delivering a closed bar
766
+
767
+ Params
768
+
769
+ - Bar2edge (default: True)
770
+
771
+ Replays using time boundaries as the target of the closed bar.For
772
+ example, with a "ticks -> 5 seconds" the resulting 5-second bars will
773
+ be aligned to xx:00, xx:05, xx:10 ...
774
+
775
+ - Adjbartime (default: False)
776
+
777
+ Use the time at the boundary to adjust the time of the delivered
778
+ resampled bar instead of the last seen timestamp. If resampling to "5
779
+ seconds" the time of the bar will be adjusted, for example, to hh:mm:05
780
+ even if the last seen timestamp was hh:mm:04.33
781
+
782
+ *Note*
783
+
784
+ Time will only be adjusted if "bar2edge" is True. It wouldn't make
785
+ sense to adjust the time if the bar has not been aligned to a
786
+ boundary
787
+
788
+ *Note* if this parameter is True, an extra tick with the *adjusted*
789
+ time will be introduced at the end of the *replayed* bar
790
+
791
+ - Rightedge (default: True)
792
+
793
+ Use the right edge of the time boundaries to set the time.
794
+
795
+ If False and compressing to 5 seconds, the time of a resampled bar for
796
+ seconds between hh:mm:00 and hh:mm:04 will be hh:mm:00 (the starting
797
+ boundary
798
+
799
+ If True, the used boundary for the time will be hh:mm:05 (the ending
800
+ boundary)
801
+ """
802
+
803
+ params = (
804
+ ("bar2edge", True),
805
+ ("adjbartime", False),
806
+ ("rightedge", True),
807
+ )
808
+
809
+ replaying = True
810
+
811
+ # Run when calling class
812
+ def __call__(self, data, fromcheck=False, forcedata=None):
813
+ """Process the data for replaying.
814
+
815
+ Manages bar replaying with session information and time alignment.
816
+
817
+ Args:
818
+ data: The data source to replay.
819
+ fromcheck: Whether this is being called from a periodic check.
820
+ forcedata: Optional data source to force timing from.
821
+
822
+ Returns:
823
+ bool: True if a new bar was generated, False otherwise.
824
+ """
825
+ # Consume
826
+ consumed = False
827
+ # At bar generation time point
828
+ onedge = False
829
+ # Late-arriving data
830
+ takinglate = False
831
+ # Whether to check bar end
832
+ docheckover = True
833
+ # If fromcheck is False
834
+ if not fromcheck:
835
+ # Call _latedata to see how to handle late data, if returns True
836
+ if self._latedata(data):
837
+ # If takelate is False, generate a new bar
838
+ if not self.p.takelate:
839
+ data.backwards(force=True)
840
+ return True # get a new bar
841
+ # Set these two parameters
842
+ consumed = True
843
+ takinglate = True
844
+ # If not intraday
845
+ elif self.componly: # only if not subdays
846
+ consumed = True
847
+
848
+ else:
849
+ # Call _dataonedge to determine if at bar generation time and if bar is over
850
+ onedge, docheckover = self._dataonedge(data) # for subdays
851
+ consumed = onedge
852
+
853
+ data._tick_fill(force=True) # update
854
+ # If consumed is True, update data, if takinglate is True, set a new time for bar
855
+ if consumed:
856
+ self.bar.bupdate(data)
857
+ if takinglate:
858
+ self.bar.datetime = data.datetime[-1] + 0.000001
859
+
860
+ # if onedge or (checkbarover and self._checkbarover)
861
+ cond = onedge
862
+ # If currently not at bar generation time point, if check is needed, need to check if bar is over
863
+ if not cond: # original is or, if true, it would suffice
864
+ if docheckover:
865
+ cond = self._checkbarover(data, fromcheck=fromcheck)
866
+ # If check result returns True
867
+ if cond:
868
+ # If not exactly at bar generation time and need to adjust time
869
+ if not onedge and self.doadjusttime: # insert tick with adjtime
870
+ adjusted = self._adjusttime(greater=True)
871
+ # If adjustment is needed, adjust time and update bar
872
+ if adjusted:
873
+ ago = 0 if (consumed or fromcheck) else -1
874
+ # Update to the point right before the new data
875
+ data._updatebar(self.bar.lvalues(), forward=False, ago=ago)
876
+ # If no check needed
877
+ if not fromcheck:
878
+ # If not in consume mode, use _save2stack to save data
879
+ if not consumed:
880
+ # Reopen bar with real new data and save data to queue
881
+ self.bar.bupdate(data, reopen=True)
882
+ # erase is True, but the tick will not be seen below
883
+ # and therefore no need to mark as 1st
884
+ data._save2stack(erase=True, force=True)
885
+ # If in consume mode, data starts, next bar is first bar
886
+ else:
887
+ self.bar.bstart(maxdate=True)
888
+ self._firstbar = True # next is first
889
+ # If check is needed
890
+ else: # from check
891
+ # fromcheck or consumed have forced delivery, reopen
892
+ self.bar.bstart(maxdate=True)
893
+ self._firstbar = True # next is first
894
+ if adjusted:
895
+ # after adjusting need to redeliver if this was a check
896
+ data._save2stack(erase=True, force=True)
897
+ # If no check needed
898
+ elif not fromcheck:
899
+ if not consumed:
900
+ # Data already "forwarded" and we replay to new bar
901
+ # No need to go backwards.reopen the internal cache
902
+ self.bar.bupdate(data, reopen=True)
903
+ else:
904
+ # compression only, used data to update bar, hence remove
905
+ # from stream, update existing data, reopen bar
906
+ if not self._firstbar: # only discard data if not firstbar
907
+ data.backwards(force=True)
908
+ data._updatebar(self.bar.lvalues(), forward=False, ago=0)
909
+ self.bar.bstart(maxdate=True)
910
+ self._firstbar = True # make sure the next tick moves forward
911
+ # If no check needed
912
+ elif not fromcheck:
913
+ # not over, update, remove new entry, deliver
914
+ if not consumed:
915
+ self.bar.bupdate(data)
916
+
917
+ if not self._firstbar: # only discard data if not firstbar
918
+ data.backwards(force=True)
919
+
920
+ data._updatebar(self.bar.lvalues(), forward=False, ago=0)
921
+ self._firstbar = False
922
+
923
+ return False # the system can process the existing bar
924
+
925
+
926
+ class ResamplerTicks(Resampler):
927
+ """Resampler for tick-level data."""
928
+
929
+ params = (("timeframe", TimeFrame.Ticks),)
930
+
931
+
932
+ class ResamplerSeconds(Resampler):
933
+ """Resampler for seconds-level data."""
934
+
935
+ params = (("timeframe", TimeFrame.Seconds),)
936
+
937
+
938
+ class ResamplerMinutes(Resampler):
939
+ """Resampler for minute-level data."""
940
+
941
+ params = (("timeframe", TimeFrame.Minutes),)
942
+
943
+
944
+ class ResamplerDaily(Resampler):
945
+ """Resampler for daily data."""
946
+
947
+ params = (("timeframe", TimeFrame.Days),)
948
+
949
+
950
+ class ResamplerWeekly(Resampler):
951
+ """Resampler for weekly data."""
952
+
953
+ params = (("timeframe", TimeFrame.Weeks),)
954
+
955
+
956
+ class ResamplerMonthly(Resampler):
957
+ """Resampler for monthly data."""
958
+
959
+ params = (("timeframe", TimeFrame.Months),)
960
+
961
+
962
+ class ResamplerYearly(Resampler):
963
+ """Resampler for yearly data."""
964
+
965
+ params = (("timeframe", TimeFrame.Years),)
966
+
967
+
968
+ class ReplayerTicks(Replayer):
969
+ """Replayer for tick-level data."""
970
+
971
+ params = (("timeframe", TimeFrame.Ticks),)
972
+
973
+
974
+ class ReplayerSeconds(Replayer):
975
+ """Replayer for seconds-level data."""
976
+
977
+ params = (("timeframe", TimeFrame.Seconds),)
978
+
979
+
980
+ class ReplayerMinutes(Replayer):
981
+ """Replayer for minute-level data."""
982
+
983
+ params = (("timeframe", TimeFrame.Minutes),)
984
+
985
+
986
+ class ReplayerDaily(Replayer):
987
+ """Replayer for daily data."""
988
+
989
+ params = (("timeframe", TimeFrame.Days),)
990
+
991
+
992
+ class ReplayerWeekly(Replayer):
993
+ """Replayer for weekly data."""
994
+
995
+ params = (("timeframe", TimeFrame.Weeks),)
996
+
997
+
998
+ class ReplayerMonthly(Replayer):
999
+ """Replayer for monthly data."""
1000
+
1001
+ params = (("timeframe", TimeFrame.Months),)