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,294 @@
1
+ """Live data validator for real-time event streams.
2
+
3
+ Validates incoming events for data quality issues such as out-of-order
4
+ timestamps, time jumps, invalid prices/volumes, and stale data detection.
5
+
6
+ Example::
7
+
8
+ validator = LiveDataValidator()
9
+ if validator.validate(event):
10
+ process(event)
11
+ else:
12
+ log_rejected(event)
13
+
14
+ print(validator.get_anomaly_report())
15
+ """
16
+
17
+ import math
18
+ import time
19
+
20
+ from ..utils.log_message import get_logger
21
+
22
+ logger = get_logger(__name__)
23
+
24
+ __all__ = ["LiveDataValidator"]
25
+
26
+
27
+ class LiveDataValidator:
28
+ """Real-time data quality validator.
29
+
30
+ Checks each incoming event for:
31
+ - Out-of-order timestamps
32
+ - Large time jumps (>1 hour by default)
33
+ - Invalid prices (<=0) or volumes (<0) for tick data
34
+ - Invalid order book structure
35
+ - Stale data detection
36
+
37
+ Args:
38
+ max_time_jump: Maximum allowed timestamp gap in seconds (default: 3600).
39
+ max_clock_drift: Maximum allowed drift from wall clock in seconds (default: 60).
40
+ enable_clock_check: Whether to check against wall clock time (default: False).
41
+ """
42
+
43
+ def __init__(self, max_time_jump=3600, max_clock_drift=60.0, enable_clock_check=False):
44
+ """Initialize the live data validator.
45
+
46
+ Args:
47
+ max_time_jump: Maximum allowed time jump between events (seconds).
48
+ max_clock_drift: Maximum allowed clock drift across symbols (seconds).
49
+ enable_clock_check: Whether to enable clock synchronization checks.
50
+ """
51
+ max_time_jump = self._coerce_number(max_time_jump)
52
+ max_clock_drift = self._coerce_number(max_clock_drift)
53
+ if max_time_jump is None or max_time_jump < 0:
54
+ raise ValueError("max_time_jump must be a non-negative number")
55
+ if max_clock_drift is None or max_clock_drift < 0:
56
+ raise ValueError("max_clock_drift must be a non-negative number")
57
+ self._max_time_jump = max_time_jump
58
+ self._max_clock_drift = max_clock_drift
59
+ self._enable_clock_check = enable_clock_check
60
+ self._last_timestamps = {}
61
+ self._anomaly_count = {}
62
+ self._total_validated = 0
63
+ self._total_rejected = 0
64
+
65
+ def validate(self, event):
66
+ """Validate an incoming event.
67
+
68
+ Args:
69
+ event: Event wrapper with timestamp, channel_type, channel_name, data.
70
+
71
+ Returns:
72
+ True if the event passes validation, False if rejected.
73
+ """
74
+ self._total_validated += 1
75
+ key = self._event_key(event)
76
+ if event is None:
77
+ self._record_anomaly(key, "invalid_event")
78
+ self._total_rejected += 1
79
+ return False
80
+ ts = self._coerce_number(getattr(event, "timestamp", None))
81
+ if ts is None or ts < 0:
82
+ self._record_anomaly(key, "invalid_timestamp")
83
+ self._total_rejected += 1
84
+ return False
85
+
86
+ # 1. Timestamp order check
87
+ last_ts = self._last_timestamps.get(key, 0)
88
+ if last_ts > 0 and ts < last_ts:
89
+ self._record_anomaly(key, "out_of_order")
90
+ self._total_rejected += 1
91
+ return False
92
+
93
+ # 2. Time jump check (warn but don't reject unless extreme)
94
+ if last_ts > 0 and ts - last_ts > self._max_time_jump:
95
+ self._record_anomaly(key, "time_jump")
96
+ logger.warning(
97
+ "Time jump detected for %s: %.1fs gap",
98
+ key,
99
+ ts - last_ts,
100
+ )
101
+
102
+ # 3. Wall clock drift check
103
+ if self._enable_clock_check:
104
+ now = time.time()
105
+ drift = abs(ts - now)
106
+ if drift > self._max_clock_drift:
107
+ self._record_anomaly(key, "clock_drift")
108
+ logger.warning(
109
+ "Clock drift for %s: %.1fs from wall clock",
110
+ key,
111
+ drift,
112
+ )
113
+
114
+ # 4. Data-specific validation
115
+ data = getattr(event, "data", None)
116
+ channel_type = getattr(event, "channel_type", "")
117
+
118
+ if data is not None:
119
+ if channel_type == "tick":
120
+ if not self._validate_tick(key, data):
121
+ self._total_rejected += 1
122
+ return False
123
+ elif channel_type == "orderbook":
124
+ if not self._validate_orderbook(key, data):
125
+ self._total_rejected += 1
126
+ return False
127
+ elif channel_type == "funding":
128
+ if not self._validate_funding(key, data):
129
+ self._total_rejected += 1
130
+ return False
131
+
132
+ self._last_timestamps[key] = ts
133
+ return True
134
+
135
+ def _validate_tick(self, key, tick):
136
+ """Validate tick data for price and volume constraints.
137
+
138
+ Checks that price is positive and volume is non-negative. Rejects
139
+ ticks that violate these constraints and records the anomaly.
140
+
141
+ Args:
142
+ key: Tuple of (channel_type, channel_name) for tracking.
143
+ tick: TickEvent instance to validate.
144
+
145
+ Returns:
146
+ True if the tick is valid, False otherwise.
147
+ """
148
+ raw_price = getattr(tick, "price", None)
149
+ raw_volume = getattr(tick, "volume", None)
150
+ price = self._coerce_number(raw_price) if raw_price is not None else None
151
+ volume = self._coerce_number(raw_volume) if raw_volume is not None else None
152
+
153
+ if raw_price is not None and (price is None or price <= 0):
154
+ self._record_anomaly(key, "invalid_price")
155
+ return False
156
+ if raw_volume is not None and (volume is None or volume < 0):
157
+ self._record_anomaly(key, "invalid_volume")
158
+ return False
159
+ return True
160
+
161
+ def _validate_orderbook(self, key, ob):
162
+ """Validate order book data structure and integrity.
163
+
164
+ Checks that the order book is not empty and that there are no
165
+ crossed books (best bid >= best ask), which would indicate
166
+ data corruption or invalid market state.
167
+
168
+ Args:
169
+ key: Tuple of (channel_type, channel_name) for tracking.
170
+ ob: OrderBookSnapshot instance to validate.
171
+
172
+ Returns:
173
+ True if the order book is valid, False otherwise.
174
+ """
175
+ bids = getattr(ob, "bids", None)
176
+ asks = getattr(ob, "asks", None)
177
+
178
+ if not bids and not asks:
179
+ self._record_anomaly(key, "empty_orderbook")
180
+ return False
181
+
182
+ # Check crossed book (best bid >= best ask)
183
+ if bids and asks:
184
+ best_bid = self._extract_orderbook_price(bids[0])
185
+ best_ask = self._extract_orderbook_price(asks[0])
186
+ if best_bid is None or best_ask is None:
187
+ self._record_anomaly(key, "invalid_orderbook_price")
188
+ return False
189
+ if best_bid >= best_ask:
190
+ self._record_anomaly(key, "crossed_book")
191
+ logger.warning(
192
+ "Crossed order book for %s: bid=%.2f >= ask=%.2f", key, best_bid, best_ask
193
+ )
194
+ return True
195
+
196
+ def _validate_funding(self, key, funding):
197
+ """Validate funding rate data for extreme values.
198
+
199
+ Checks if the funding rate is within reasonable bounds
200
+ (absolute value <= 0.1). Extreme funding rates are logged
201
+ as warnings but not rejected.
202
+
203
+ Args:
204
+ key: Tuple of (channel_type, channel_name) for tracking.
205
+ funding: FundingEvent instance to validate.
206
+
207
+ Returns:
208
+ Always returns True (warnings are logged, not rejected).
209
+ """
210
+ raw_rate = getattr(funding, "rate", None)
211
+ if raw_rate is None:
212
+ return True
213
+ rate = self._coerce_number(raw_rate)
214
+ if rate is None:
215
+ self._record_anomaly(key, "invalid_funding_rate")
216
+ return False
217
+ if abs(rate) > 0.1:
218
+ self._record_anomaly(key, "extreme_funding_rate")
219
+ logger.warning("Extreme funding rate for %s: %.6f", key, rate)
220
+ return True
221
+
222
+ @staticmethod
223
+ def _coerce_number(value):
224
+ if isinstance(value, bool):
225
+ return None
226
+ try:
227
+ number = float(value)
228
+ except (TypeError, ValueError):
229
+ return None
230
+ if not math.isfinite(number):
231
+ return None
232
+ return number
233
+
234
+ @staticmethod
235
+ def _event_key(event):
236
+ return (
237
+ str(getattr(event, "channel_type", "") or ""),
238
+ str(getattr(event, "channel_name", "") or ""),
239
+ )
240
+
241
+ def _extract_orderbook_price(self, level):
242
+ if isinstance(level, (list, tuple)):
243
+ if not level:
244
+ return None
245
+ return self._coerce_number(level[0])
246
+ return self._coerce_number(getattr(level, "price", None))
247
+
248
+ def _record_anomaly(self, key, anomaly_type):
249
+ """Record an anomaly occurrence for later reporting.
250
+
251
+ Args:
252
+ key: Tuple of (channel_type, channel_name) for tracking.
253
+ anomaly_type: String identifying the type of anomaly.
254
+ """
255
+ if key not in self._anomaly_count:
256
+ self._anomaly_count[key] = {}
257
+ self._anomaly_count[key][anomaly_type] = self._anomaly_count[key].get(anomaly_type, 0) + 1
258
+
259
+ def get_anomaly_report(self):
260
+ """Get the anomaly report.
261
+
262
+ Returns:
263
+ Dict mapping (channel_type, channel_name) to {anomaly_type: count}.
264
+ """
265
+ return dict(self._anomaly_count)
266
+
267
+ @property
268
+ def stats(self):
269
+ """Validation statistics."""
270
+ return {
271
+ "total_validated": self._total_validated,
272
+ "total_rejected": self._total_rejected,
273
+ "rejection_rate": (
274
+ self._total_rejected / self._total_validated if self._total_validated > 0 else 0.0
275
+ ),
276
+ "anomaly_types": {str(k): v for k, v in self._anomaly_count.items()},
277
+ }
278
+
279
+ def reset(self):
280
+ """Reset all state."""
281
+ self._last_timestamps.clear()
282
+ self._anomaly_count.clear()
283
+ self._total_validated = 0
284
+ self._total_rejected = 0
285
+
286
+ def __repr__(self):
287
+ """Return a string representation of the validator.
288
+
289
+ Returns:
290
+ str: Representation showing validation statistics.
291
+ """
292
+ return (
293
+ f"LiveDataValidator(validated={self._total_validated}, rejected={self._total_rejected})"
294
+ )
@@ -0,0 +1,257 @@
1
+ """OrderBook data channel for order book depth snapshots.
2
+
3
+ Provides OrderBookChannel for loading, validating, and buffering order book
4
+ data from CSV/JSONL files or other sources.
5
+
6
+ Example:
7
+ Loading order book data from CSV::
8
+
9
+ channel = OrderBookChannel(
10
+ symbol='BTC/USDT',
11
+ dataname='data/btc_ob_20210101.csv',
12
+ depth=20
13
+ )
14
+ for event in channel.load():
15
+ print(event.best_bid, event.best_ask, event.spread)
16
+ """
17
+
18
+ import csv
19
+ import gzip
20
+ import json
21
+ import math
22
+ from typing import IO, Iterator, List, Tuple
23
+
24
+ from ..channel import DataChannel, DataValidationResult
25
+ from ..events import OrderBookSnapshot
26
+ from ..utils.log_message import get_logger
27
+
28
+ logger = get_logger(__name__)
29
+
30
+
31
+ class OrderBookChannel(DataChannel):
32
+ """Order book depth snapshot channel.
33
+
34
+ Loads order book data from CSV or JSONL files. Supports configurable
35
+ depth levels and validates bid/ask ordering and spread.
36
+
37
+ CSV format expects columns: timestamp, bids, asks
38
+ where bids/asks are JSON-encoded lists of [price, qty] pairs.
39
+
40
+ JSONL format expects one JSON object per line with fields:
41
+ timestamp, symbol, bids, asks.
42
+
43
+ Args:
44
+ symbol: Trading pair symbol (e.g., 'BTC/USDT').
45
+ dataname: Path to the data file (CSV or JSONL).
46
+ depth: Maximum order book depth to retain.
47
+ maxlen: Maximum buffer size.
48
+ validate: Whether to validate incoming events.
49
+ auto_fix: Whether to auto-fix invalid data.
50
+ **kwargs: Additional parameters passed to DataChannel.
51
+ """
52
+
53
+ channel_type = "orderbook"
54
+
55
+ def __init__(
56
+ self, symbol, dataname=None, depth=20, maxlen=10000, validate=True, auto_fix=True, **kwargs
57
+ ):
58
+ """Initialize the order book channel.
59
+
60
+ Args:
61
+ symbol: Trading pair symbol (e.g., 'BTC/USDT:USDT').
62
+ dataname: Optional data name for the feed.
63
+ depth: Order book depth (number of price levels).
64
+ maxlen: Maximum number of events to buffer.
65
+ validate: Whether to validate incoming events.
66
+ auto_fix: Whether to attempt auto-fixing invalid data.
67
+ **kwargs: Additional arguments passed to parent.
68
+ """
69
+ super().__init__(
70
+ symbol=symbol,
71
+ maxlen=maxlen,
72
+ validate=validate,
73
+ auto_fix=auto_fix,
74
+ dataname=dataname,
75
+ **kwargs,
76
+ )
77
+ self._dataname = dataname
78
+ self._depth = depth
79
+ self._last_best_bid = None
80
+ self._last_best_ask = None
81
+
82
+ @property
83
+ def depth(self):
84
+ """Configured maximum order book depth."""
85
+ return self._depth
86
+
87
+ def _validate_event(self, event) -> DataValidationResult:
88
+ """Validate order book specific fields beyond base validation.
89
+
90
+ Additional checks:
91
+ - Spread consistency with previous snapshots
92
+ - Depth within configured limits
93
+ """
94
+ result = super()._validate_event(event)
95
+ if not result.valid:
96
+ return result
97
+
98
+ # Truncate to configured depth
99
+ if len(event.bids) > self._depth:
100
+ event.bids = event.bids[: self._depth]
101
+ if len(event.asks) > self._depth:
102
+ event.asks = event.asks[: self._depth]
103
+
104
+ # Track best bid/ask for anomaly detection
105
+ if event.bids and event.asks:
106
+ self._last_best_bid = event.bids[0][0]
107
+ self._last_best_ask = event.asks[0][0]
108
+
109
+ return result
110
+
111
+ def load(self) -> Iterator[OrderBookSnapshot]:
112
+ """Load order book events from file.
113
+
114
+ Supports CSV and JSONL formats. File format is auto-detected
115
+ by extension (.jsonl or .csv/.csv.gz).
116
+
117
+ Yields:
118
+ OrderBookSnapshot instances.
119
+ """
120
+ dataname = self._dataname
121
+ if dataname is None:
122
+ raise ValueError("dataname (file path) is required for loading")
123
+
124
+ if dataname.endswith((".jsonl", ".jsonl.gz")):
125
+ yield from self._load_jsonl()
126
+ else:
127
+ yield from self._load_csv()
128
+
129
+ def _load_csv(self) -> Iterator[OrderBookSnapshot]:
130
+ """Load order book events from CSV format.
131
+
132
+ Supports both plain CSV and gzip-compressed CSV (.csv.gz).
133
+ Expects columns: timestamp, bids, asks (where bids/asks are
134
+ JSON-encoded lists of [price, qty] pairs).
135
+
136
+ Yields:
137
+ OrderBookSnapshot instances.
138
+ """
139
+ dataname = self._dataname
140
+ if dataname is None:
141
+ raise ValueError("dataname (file path) is required for loading")
142
+
143
+ csv_file: IO[str]
144
+ if dataname.endswith(".gz"):
145
+ csv_file = gzip.open(dataname, mode="rt", encoding="utf-8")
146
+ else:
147
+ csv_file = open(dataname, mode="r", encoding="utf-8", newline="")
148
+
149
+ with csv_file as f:
150
+ reader = csv.DictReader(f)
151
+
152
+ required = {"timestamp", "bids", "asks"}
153
+ if reader.fieldnames:
154
+ missing = required - set(reader.fieldnames)
155
+ if missing:
156
+ raise ValueError(
157
+ f"Missing required columns: {missing}. Found: {reader.fieldnames}"
158
+ )
159
+
160
+ for row in reader:
161
+ try:
162
+ bids = _parse_levels(row["bids"])
163
+ asks = _parse_levels(row["asks"])
164
+
165
+ ob = OrderBookSnapshot(
166
+ timestamp=_parse_required_float(row["timestamp"]),
167
+ symbol=row.get("symbol", self.symbol),
168
+ exchange=row.get("exchange", ""),
169
+ asset_type=row.get("asset_type", "spot"),
170
+ bids=bids[: self._depth],
171
+ asks=asks[: self._depth],
172
+ )
173
+ yield ob
174
+ except (ValueError, KeyError, json.JSONDecodeError) as e:
175
+ logger.warning("Skipping invalid OB row: %s (error: %s)", row, e)
176
+ continue
177
+
178
+ def _load_jsonl(self) -> Iterator[OrderBookSnapshot]:
179
+ """Load order book events from JSONL format.
180
+
181
+ Supports both plain JSONL and gzip-compressed JSONL (.jsonl.gz).
182
+ Each line should contain a JSON object with timestamp, symbol,
183
+ bids, and asks fields.
184
+
185
+ Yields:
186
+ OrderBookSnapshot instances.
187
+ """
188
+ dataname = self._dataname
189
+ if dataname is None:
190
+ raise ValueError("dataname (file path) is required for loading")
191
+
192
+ jsonl_file: IO[str] = (
193
+ gzip.open(dataname, mode="rt", encoding="utf-8")
194
+ if dataname.endswith(".gz")
195
+ else open(dataname, mode="r", encoding="utf-8")
196
+ )
197
+
198
+ with jsonl_file as f:
199
+ for line_num, line in enumerate(f, 1):
200
+ line = line.strip()
201
+ if not line:
202
+ continue
203
+ try:
204
+ data = json.loads(line)
205
+ bids = _parse_level_pairs(data.get("bids", []))
206
+ asks = _parse_level_pairs(data.get("asks", []))
207
+
208
+ ob = OrderBookSnapshot(
209
+ timestamp=_parse_required_float(data["timestamp"]),
210
+ symbol=data.get("symbol", self.symbol),
211
+ exchange=data.get("exchange", ""),
212
+ asset_type=data.get("asset_type", "spot"),
213
+ bids=bids[: self._depth],
214
+ asks=asks[: self._depth],
215
+ )
216
+ yield ob
217
+ except (ValueError, KeyError, json.JSONDecodeError) as e:
218
+ logger.warning("Skipping invalid OB JSONL line %d: %s", line_num, e)
219
+ continue
220
+
221
+ def __repr__(self):
222
+ """Return a string representation of the channel.
223
+
224
+ Returns:
225
+ str: Representation showing symbol, depth, and buffer stats.
226
+ """
227
+ return (
228
+ f"OrderBookChannel(symbol={self.symbol!r}, "
229
+ f"depth={self._depth}, "
230
+ f"dataname={self._dataname!r}, "
231
+ f"events={self._event_count}, "
232
+ f"buffered={len(self._buffer)})"
233
+ )
234
+
235
+
236
+ def _parse_levels(text: str) -> List[Tuple[float, float]]:
237
+ """Parse order book levels from JSON string.
238
+
239
+ Args:
240
+ text: JSON string like '[[50000, 1.0], [49999, 2.0]]'
241
+
242
+ Returns:
243
+ List of (price, quantity) tuples.
244
+ """
245
+ levels = json.loads(text)
246
+ return _parse_level_pairs(levels)
247
+
248
+
249
+ def _parse_required_float(value) -> float:
250
+ number = float(value)
251
+ if not math.isfinite(number):
252
+ raise ValueError(f"Non-finite float value: {value}")
253
+ return number
254
+
255
+
256
+ def _parse_level_pairs(levels) -> List[Tuple[float, float]]:
257
+ return [(_parse_required_float(p), _parse_required_float(q)) for p, q in levels]