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,625 @@
1
+ """Binance BBO/depth data loading for HFT backtesting.
2
+
3
+ Parses Binance best-bid/offer and depth/trade dumps (CSV/JSON/zip) into the
4
+ event format consumed by the tick-level matching engine, optionally bridging to
5
+ ``hftbacktest``'s ``FuseMarketDepth`` when available.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import bisect
11
+ import csv
12
+ import io
13
+ import json
14
+ import re
15
+ import zipfile
16
+ from dataclasses import dataclass
17
+ from pathlib import Path
18
+ from typing import Iterable, Iterator, Optional
19
+
20
+ import numpy as np
21
+
22
+ from ...utils.log_message import get_logger
23
+
24
+ logger = get_logger(__name__)
25
+
26
+ try:
27
+ from hftbacktest import FuseMarketDepth
28
+ except Exception:
29
+ logger.warning("binance_bbo:24 fallback on Exception")
30
+ FuseMarketDepth = None
31
+
32
+ EXCH_EVENT = 1 << 31
33
+ LOCAL_EVENT = 1 << 30
34
+ BUY_EVENT = 1 << 29
35
+ SELL_EVENT = 1 << 28
36
+ DEPTH_EVENT = 1
37
+ TRADE_EVENT = 2
38
+ DEPTH_BBO_EVENT = 5
39
+
40
+ EVENT_DTYPE = np.dtype(
41
+ [
42
+ ("ev", "u8"),
43
+ ("exch_ts", "i8"),
44
+ ("local_ts", "i8"),
45
+ ("px", "f8"),
46
+ ("qty", "f8"),
47
+ ("order_id", "u8"),
48
+ ("ival", "i8"),
49
+ ("fval", "f8"),
50
+ ],
51
+ align=True,
52
+ )
53
+
54
+ _LATENCY_DTYPE = np.dtype(
55
+ [("req_ts", "i8"), ("exch_ts", "i8"), ("resp_ts", "i8"), ("_padding", "i8")],
56
+ align=True,
57
+ )
58
+
59
+ _FILENAME_RE = re.compile(
60
+ r"^(?P<symbol>[A-Z0-9]+)-(?P<kind>[A-Za-z]+)-(?P<date>\d{4}-\d{2}-\d{2})\.zip$"
61
+ )
62
+
63
+
64
+ @dataclass(frozen=True)
65
+ class BinanceBBOConversionResult:
66
+ """Result of converting a Binance BBO + trades zip pair.
67
+
68
+ Attributes:
69
+ symbol: Native exchange symbol extracted from the input zip
70
+ filename (for example ``"BTCUSDT"``).
71
+ bt_symbol: Backtrader-style symbol used for the generated tick
72
+ CSV and order-book JSONL files. Defaults to the
73
+ :func:`_default_bt_symbol` mapping if the caller did not
74
+ pass an explicit value.
75
+ date: ISO-style date (``YYYY-MM-DD``) parsed from the input zip
76
+ filename.
77
+ hft_npz_path: Path of the consolidated ``.npz`` file containing
78
+ the unified feed stream that downstream HFT tooling
79
+ (latency generators, matching engine) consumes.
80
+ backtrader_ticks_path: Path of the generated Backtrader tick
81
+ CSV file.
82
+ backtrader_orderbook_path: Path of the generated Backtrader
83
+ order-book JSONL file.
84
+ base_event_count: Number of raw feed events read from the input
85
+ zip files before the ``start_ms`` / ``end_ms`` window was
86
+ applied.
87
+ final_event_count: Number of events written to ``hft_npz_path``
88
+ after windowing, deduplication and book/trade merging.
89
+ book_rows: Number of best-bid/best-ask rows actually written to
90
+ ``backtrader_orderbook_path``.
91
+ trade_rows: Number of trade rows actually written to
92
+ ``backtrader_ticks_path``.
93
+ """
94
+
95
+ symbol: str
96
+ bt_symbol: str
97
+ date: str
98
+ hft_npz_path: Path
99
+ backtrader_ticks_path: Path
100
+ backtrader_orderbook_path: Path
101
+ base_event_count: int
102
+ final_event_count: int
103
+ book_rows: int
104
+ trade_rows: int
105
+
106
+
107
+ @dataclass(frozen=True)
108
+ class BinanceBBOLatencyResult:
109
+ """Result of :func:`generate_latency_from_hft_events`.
110
+
111
+ Attributes:
112
+ latency_npz_path: Path of the ``.npz`` file containing the
113
+ synthesised latency record. The file holds a single
114
+ ``data`` array with the dtype defined by
115
+ ``_LATENCY_DTYPE``.
116
+ row_count: Number of latency rows actually written to
117
+ ``latency_npz_path`` — i.e. the number of dual-marked feed
118
+ events that were turned into latency records.
119
+ """
120
+
121
+ latency_npz_path: Path
122
+ row_count: int
123
+
124
+
125
+ @dataclass(frozen=True)
126
+ class _BookRow:
127
+ exch_ms: int
128
+ local_ms: int
129
+ bid_price: float
130
+ bid_qty: float
131
+ ask_price: float
132
+ ask_qty: float
133
+
134
+
135
+ def convert_binance_bbo_zip_pair(
136
+ book_ticker_zip_path,
137
+ trades_zip_path,
138
+ output_directory,
139
+ bt_symbol: Optional[str] = None,
140
+ exchange: str = "binance",
141
+ asset_type: str = "futures",
142
+ start_ms: Optional[int] = None,
143
+ end_ms: Optional[int] = None,
144
+ max_book_rows: Optional[int] = None,
145
+ max_trade_rows: Optional[int] = None,
146
+ tick_size: float = 0.01,
147
+ lot_size: float = 0.001,
148
+ ) -> BinanceBBOConversionResult:
149
+ """Convert a Binance ``bookTicker`` + trades zip pair into HFT-ready artifacts.
150
+
151
+ The function reads the two zip archives produced by Binance's
152
+ public data export, applies an optional time window, and emits
153
+ three files inside ``output_directory``:
154
+
155
+ * a Backtrader-friendly tick CSV (``backtrader_ticks_path``),
156
+ * a Backtrader-friendly best-bid/ask JSONL stream
157
+ (``backtrader_orderbook_path``),
158
+ * a consolidated ``.npz`` file (``hft_npz_path``) used by the rest
159
+ of the HFT stack (latency synthesis, matching engine playback,
160
+ branch comparison).
161
+
162
+ Args:
163
+ book_ticker_zip_path: Path of the ``bookTicker`` zip archive
164
+ exported by Binance. The filename must match the
165
+ ``<SYMBOL>-bookTicker-<DATE>.zip`` convention enforced by
166
+ ``_SYMBOL_DATE_RE``.
167
+ trades_zip_path: Path of the matching ``trades`` zip archive.
168
+ Must share both the symbol and date of
169
+ ``book_ticker_zip_path``.
170
+ output_directory: Destination directory. Created with
171
+ ``parents=True`` if it does not already exist.
172
+ bt_symbol: Backtrader-style symbol written to the output files.
173
+ When ``None`` (the default) it is derived from ``symbol``
174
+ via :func:`_default_bt_symbol`.
175
+ exchange: Exchange tag written into the tick CSV.
176
+ asset_type: Asset-class tag written into the tick CSV
177
+ (``"futures"``, ``"spot"`` ...).
178
+ start_ms: Optional inclusive lower bound (epoch ms) for the
179
+ events to keep. ``None`` keeps everything from the start of
180
+ the archive.
181
+ end_ms: Optional inclusive upper bound (epoch ms) for the events
182
+ to keep. ``None`` keeps everything until the end of the
183
+ archive.
184
+ max_book_rows: Optional cap on the number of book rows written
185
+ to the order-book JSONL file (useful for tests).
186
+ max_trade_rows: Optional cap on the number of trade rows written
187
+ to the tick CSV (useful for tests).
188
+ tick_size: Minimum price increment for the symbol. Currently
189
+ informational — written into the consolidated ``.npz``
190
+ metadata so downstream consumers can use it.
191
+ lot_size: Minimum quantity increment for the symbol. Currently
192
+ informational — written into the consolidated ``.npz``
193
+ metadata so downstream consumers can use it.
194
+
195
+ Returns:
196
+ BinanceBBOConversionResult: Paths of every artifact that was
197
+ written together with the row/event counts for quick
198
+ verification.
199
+
200
+ Raises:
201
+ ValueError: If ``book_ticker_zip_path`` and ``trades_zip_path``
202
+ do not share the same symbol and date.
203
+ """
204
+ book_ticker_zip_path = Path(book_ticker_zip_path)
205
+ trades_zip_path = Path(trades_zip_path)
206
+ output_directory = Path(output_directory)
207
+ output_directory.mkdir(parents=True, exist_ok=True)
208
+
209
+ symbol, date = _extract_symbol_and_date(book_ticker_zip_path)
210
+ trade_symbol, trade_date = _extract_symbol_and_date(trades_zip_path)
211
+ if trade_symbol != symbol or trade_date != date:
212
+ raise ValueError("bookTicker and trades zip files must have the same symbol and date")
213
+
214
+ bt_symbol = bt_symbol or _default_bt_symbol(symbol)
215
+
216
+ ticks_path = output_directory / f"tick_{symbol}_{date.replace('-', '')}.csv"
217
+ orderbook_path = output_directory / f"orderbook_{symbol}_{date.replace('-', '')}.jsonl"
218
+ hft_npz_path = output_directory / f"{symbol}_{date.replace('-', '')}.npz"
219
+
220
+ depth_events = []
221
+ trade_events = []
222
+ book_rows = []
223
+ latency_lookup_ts = []
224
+ latency_lookup_ms = []
225
+
226
+ with ticks_path.open("w", encoding="utf-8", newline="") as tick_file, orderbook_path.open(
227
+ "w", encoding="utf-8"
228
+ ) as orderbook_file:
229
+ tick_writer = csv.DictWriter(
230
+ tick_file,
231
+ fieldnames=[
232
+ "timestamp",
233
+ "symbol",
234
+ "exchange",
235
+ "asset_type",
236
+ "price",
237
+ "volume",
238
+ "direction",
239
+ "trade_id",
240
+ "bid_price",
241
+ "ask_price",
242
+ "bid_volume",
243
+ "ask_volume",
244
+ ],
245
+ )
246
+ tick_writer.writeheader()
247
+
248
+ for row in _iter_book_ticker_rows(book_ticker_zip_path):
249
+ exch_ms = row["transaction_time"]
250
+ if not _in_window(exch_ms, start_ms, end_ms):
251
+ continue
252
+ local_ms = max(row["event_time"], exch_ms)
253
+ book_row = _BookRow(
254
+ exch_ms=exch_ms,
255
+ local_ms=local_ms,
256
+ bid_price=row["best_bid_price"],
257
+ bid_qty=row["best_bid_qty"],
258
+ ask_price=row["best_ask_price"],
259
+ ask_qty=row["best_ask_qty"],
260
+ )
261
+ book_rows.append(book_row)
262
+ latency_lookup_ts.append(exch_ms)
263
+ latency_lookup_ms.append(local_ms - exch_ms)
264
+ depth_events.append(
265
+ (
266
+ DEPTH_BBO_EVENT | SELL_EVENT,
267
+ exch_ms * 1_000_000,
268
+ local_ms * 1_000_000,
269
+ book_row.ask_price,
270
+ book_row.ask_qty,
271
+ 0,
272
+ 0,
273
+ 0.0,
274
+ )
275
+ )
276
+ depth_events.append(
277
+ (
278
+ DEPTH_BBO_EVENT | BUY_EVENT,
279
+ exch_ms * 1_000_000,
280
+ local_ms * 1_000_000,
281
+ book_row.bid_price,
282
+ book_row.bid_qty,
283
+ 0,
284
+ 0,
285
+ 0.0,
286
+ )
287
+ )
288
+ if max_book_rows is not None and len(book_rows) >= max_book_rows:
289
+ break
290
+
291
+ if not book_rows:
292
+ raise ValueError("No bookTicker rows matched the selected window")
293
+
294
+ book_rows.sort(key=lambda row: (row.local_ms, row.exch_ms))
295
+ for book_row in book_rows:
296
+ orderbook_file.write(
297
+ json.dumps(
298
+ {
299
+ "timestamp": book_row.local_ms / 1000.0,
300
+ "symbol": bt_symbol,
301
+ "exchange": exchange,
302
+ "asset_type": asset_type,
303
+ "bids": [[book_row.bid_price, book_row.bid_qty]],
304
+ "asks": [[book_row.ask_price, book_row.ask_qty]],
305
+ },
306
+ separators=(",", ":"),
307
+ )
308
+ + "\n"
309
+ )
310
+
311
+ book_event_times = [row.local_ms for row in book_rows]
312
+
313
+ trade_rows = 0
314
+ for row in _iter_trades_rows(trades_zip_path):
315
+ exch_ms = row["time"]
316
+ if not _in_window(exch_ms, start_ms, end_ms):
317
+ continue
318
+ latency_ms = _lookup_latency_ms(exch_ms, latency_lookup_ts, latency_lookup_ms)
319
+ local_ms = exch_ms + latency_ms
320
+ side = "sell" if row["is_buyer_maker"] else "buy"
321
+ trade_flag = SELL_EVENT if side == "sell" else BUY_EVENT
322
+ book_row = _lookup_book_row(local_ms, book_event_times, book_rows)
323
+ tick_writer.writerow(
324
+ {
325
+ "timestamp": f"{local_ms / 1000.0:.6f}",
326
+ "symbol": bt_symbol,
327
+ "exchange": exchange,
328
+ "asset_type": asset_type,
329
+ "price": _format_decimal(row["price"]),
330
+ "volume": _format_decimal(row["qty"]),
331
+ "direction": side,
332
+ "trade_id": row["id"],
333
+ "bid_price": _format_decimal(book_row.bid_price),
334
+ "ask_price": _format_decimal(book_row.ask_price),
335
+ "bid_volume": _format_decimal(book_row.bid_qty),
336
+ "ask_volume": _format_decimal(book_row.ask_qty),
337
+ }
338
+ )
339
+ trade_events.append(
340
+ (
341
+ TRADE_EVENT | trade_flag,
342
+ exch_ms * 1_000_000,
343
+ local_ms * 1_000_000,
344
+ row["price"],
345
+ row["qty"],
346
+ 0,
347
+ 0,
348
+ 0.0,
349
+ )
350
+ )
351
+ trade_rows += 1
352
+ if max_trade_rows is not None and trade_rows >= max_trade_rows:
353
+ break
354
+
355
+ depth_array = np.array(depth_events, dtype=EVENT_DTYPE)
356
+ trade_array = np.array(trade_events, dtype=EVENT_DTYPE)
357
+ fused_depth_array = _fuse_depth_events(depth_array, tick_size=tick_size, lot_size=lot_size)
358
+ base_array = np.empty(len(trade_array) + len(fused_depth_array), dtype=EVENT_DTYPE)
359
+ if len(trade_array) > 0:
360
+ base_array[: len(trade_array)] = trade_array
361
+ if len(fused_depth_array) > 0:
362
+ base_array[len(trade_array) :] = fused_depth_array
363
+ base_array = _correct_local_timestamp(base_array)
364
+ data = _correct_event_order(base_array)
365
+ np.savez_compressed(hft_npz_path, data=data)
366
+
367
+ return BinanceBBOConversionResult(
368
+ symbol=symbol,
369
+ bt_symbol=bt_symbol,
370
+ date=date,
371
+ hft_npz_path=hft_npz_path,
372
+ backtrader_ticks_path=ticks_path,
373
+ backtrader_orderbook_path=orderbook_path,
374
+ base_event_count=len(base_array),
375
+ final_event_count=len(data),
376
+ book_rows=len(book_rows),
377
+ trade_rows=trade_rows,
378
+ )
379
+
380
+
381
+ def generate_latency_from_hft_events(
382
+ hft_npz_path,
383
+ output_path,
384
+ mul_entry: float = 4.0,
385
+ offset_entry_ns: int = 0,
386
+ mul_resp: float = 3.0,
387
+ offset_resp_ns: int = 0,
388
+ ) -> BinanceBBOLatencyResult:
389
+ """Synthesize a latency record from the dual-marked events of an HFT feed.
390
+
391
+ Only feed events that carry both the ``EXCH_EVENT`` and ``LOCAL_EVENT``
392
+ bits are considered (these are the rows that carry both the local
393
+ receive timestamp and the upstream exchange timestamp). For each such
394
+ row the function produces a latency tuple of
395
+ ``(req_ts, exch_ts, resp_ts, reserved)`` where:
396
+
397
+ * ``req_ts`` is the local timestamp at which the strategy requested
398
+ the action,
399
+ * ``exch_ts`` is the exchange-side arrival timestamp computed as
400
+ ``local_ts + feed_latency * mul_entry + offset_entry_ns``,
401
+ * ``resp_ts`` is the response-side arrival timestamp computed as
402
+ ``exch_ts + feed_latency * mul_resp + offset_resp_ns``.
403
+
404
+ The numpy scalars in the input file are converted to ``int`` so the
405
+ output array has fixed-width integer fields.
406
+
407
+ Args:
408
+ hft_npz_path: Path of the HFT ``.npz`` produced by
409
+ :func:`convert_binance_bbo_zip_pair`. The function looks for
410
+ the ``"data"`` array inside the archive.
411
+ output_path: Path of the latency ``.npz`` file to write. The
412
+ parent directory is created with ``parents=True`` if it does
413
+ not already exist. The file is written via
414
+ ``np.savez_compressed`` and stores a single ``"data"`` array
415
+ using ``_LATENCY_DTYPE``.
416
+ mul_entry: Multiplier applied to the observed feed latency when
417
+ computing ``exch_ts``. Defaults to ``4.0``.
418
+ offset_entry_ns: Constant offset (ns) added to the entry
419
+ latency. Useful to inject a synthetic jitter or align the
420
+ latency trace against a benchmark. Defaults to ``0``.
421
+ mul_resp: Multiplier applied to the observed feed latency when
422
+ computing ``resp_ts``. Defaults to ``3.0``.
423
+ offset_resp_ns: Constant offset (ns) added to the response
424
+ latency. Defaults to ``0``.
425
+
426
+ Returns:
427
+ BinanceBBOLatencyResult: Path of the latency file and the
428
+ number of rows written.
429
+
430
+ Raises:
431
+ ValueError: If the input ``.npz`` does not contain any
432
+ dual-marked feed events.
433
+ """
434
+ hft_npz_path = Path(hft_npz_path)
435
+ output_path = Path(output_path)
436
+ data = np.load(hft_npz_path)["data"]
437
+ mask = (data["ev"] & EXCH_EVENT == EXCH_EVENT) & (data["ev"] & LOCAL_EVENT == LOCAL_EVENT)
438
+ rows = data[mask]
439
+ if len(rows) == 0:
440
+ raise ValueError("No dual-marked feed events available for latency generation")
441
+
442
+ order_latency = np.zeros(
443
+ len(rows),
444
+ dtype=_LATENCY_DTYPE,
445
+ )
446
+ for index, row in enumerate(rows):
447
+ feed_latency = max(int(row["local_ts"] - row["exch_ts"]), 0)
448
+ entry_latency = int(feed_latency * mul_entry) + int(offset_entry_ns)
449
+ resp_latency = int(feed_latency * mul_resp) + int(offset_resp_ns)
450
+ req_ts = int(row["local_ts"])
451
+ exch_ts = req_ts + entry_latency
452
+ resp_ts = exch_ts + resp_latency
453
+ order_latency[index] = (req_ts, exch_ts, resp_ts, 0)
454
+
455
+ output_path.parent.mkdir(parents=True, exist_ok=True)
456
+ np.savez_compressed(output_path, data=order_latency)
457
+ return BinanceBBOLatencyResult(latency_npz_path=output_path, row_count=len(order_latency))
458
+
459
+
460
+ def _iter_book_ticker_rows(zip_path: Path) -> Iterator[dict]:
461
+ for row in _iter_zip_csv_rows(zip_path):
462
+ yield {
463
+ "transaction_time": int(row["transaction_time"]),
464
+ "event_time": int(row["event_time"]),
465
+ "best_bid_price": float(row["best_bid_price"]),
466
+ "best_bid_qty": float(row["best_bid_qty"]),
467
+ "best_ask_price": float(row["best_ask_price"]),
468
+ "best_ask_qty": float(row["best_ask_qty"]),
469
+ }
470
+
471
+
472
+ def _iter_trades_rows(zip_path: Path) -> Iterator[dict]:
473
+ for row in _iter_zip_csv_rows(zip_path):
474
+ yield {
475
+ "id": row["id"],
476
+ "price": float(row["price"]),
477
+ "qty": float(row["qty"]),
478
+ "time": int(row["time"]),
479
+ "is_buyer_maker": row["is_buyer_maker"].strip().lower() == "true",
480
+ }
481
+
482
+
483
+ def _iter_zip_csv_rows(zip_path: Path) -> Iterable[dict]:
484
+ with zipfile.ZipFile(zip_path) as archive:
485
+ names = [name for name in archive.namelist() if name.lower().endswith(".csv")]
486
+ if len(names) != 1:
487
+ raise ValueError(f"Expected exactly one CSV entry in {zip_path}")
488
+ with archive.open(names[0], "r") as raw:
489
+ text_stream = io.TextIOWrapper(raw, encoding="utf-8", newline="")
490
+ reader = csv.DictReader(text_stream)
491
+ for row in reader:
492
+ yield row
493
+
494
+
495
+ def _extract_symbol_and_date(zip_path: Path) -> tuple[str, str]:
496
+ match = _FILENAME_RE.match(zip_path.name)
497
+ if match is None:
498
+ raise ValueError(f"Unsupported zip filename format: {zip_path.name}")
499
+ return match.group("symbol"), match.group("date")
500
+
501
+
502
+ def _default_bt_symbol(symbol: str) -> str:
503
+ for quote in ("USDT", "USDC", "BUSD", "FDUSD", "BTC", "ETH", "BNB"):
504
+ if symbol.endswith(quote) and len(symbol) > len(quote):
505
+ return f"{symbol[: -len(quote)]}/{quote}"
506
+ return symbol
507
+
508
+
509
+ def _in_window(timestamp_ms: int, start_ms: Optional[int], end_ms: Optional[int]) -> bool:
510
+ if start_ms is not None and timestamp_ms < start_ms:
511
+ return False
512
+ if end_ms is not None and timestamp_ms > end_ms:
513
+ return False
514
+ return True
515
+
516
+
517
+ def _lookup_latency_ms(timestamp_ms: int, lookup_ts: list[int], lookup_latency: list[int]) -> int:
518
+ if not lookup_ts:
519
+ return 0
520
+ index = bisect.bisect_right(lookup_ts, timestamp_ms) - 1
521
+ if index < 0:
522
+ return lookup_latency[0]
523
+ return lookup_latency[index]
524
+
525
+
526
+ def _lookup_book_row(
527
+ timestamp_ms: int, book_event_times: list[int], book_rows: list[_BookRow]
528
+ ) -> _BookRow:
529
+ index = bisect.bisect_right(book_event_times, timestamp_ms) - 1
530
+ if index < 0:
531
+ return book_rows[0]
532
+ return book_rows[index]
533
+
534
+
535
+ def _format_decimal(value: float) -> str:
536
+ return format(value, ".15g")
537
+
538
+
539
+ def _fuse_depth_events(depth_array: np.ndarray, tick_size: float, lot_size: float) -> np.ndarray:
540
+ if len(depth_array) == 0:
541
+ return depth_array
542
+ if FuseMarketDepth is None:
543
+ fused = depth_array.copy()
544
+ fused["ev"] = (fused["ev"] & ~np.uint64(DEPTH_BBO_EVENT)) | np.uint64(DEPTH_EVENT)
545
+ return fused
546
+
547
+ fuse = FuseMarketDepth(float(tick_size), float(lot_size))
548
+ try:
549
+ for index in range(len(depth_array)):
550
+ fuse.process_event(depth_array, index, True)
551
+ return np.array(fuse.fused_events, dtype=EVENT_DTYPE, copy=True)
552
+ finally:
553
+ fuse.close()
554
+
555
+
556
+ def _correct_local_timestamp(base_array: np.ndarray, base_latency_ns: int = 0) -> np.ndarray:
557
+ if len(base_array) == 0:
558
+ return base_array
559
+ min_latency = int(np.min(base_array["local_ts"] - base_array["exch_ts"]))
560
+ if min_latency >= 0:
561
+ return base_array
562
+ corrected = base_array.copy()
563
+ corrected["local_ts"] += -min_latency + int(base_latency_ns)
564
+ return corrected
565
+
566
+
567
+ def _correct_event_order(base_array: np.ndarray) -> np.ndarray:
568
+ sorted_exch_index = np.argsort(base_array["exch_ts"], kind="mergesort")
569
+ sorted_local_index = np.argsort(base_array["local_ts"], kind="mergesort")
570
+ output = np.zeros(len(base_array) * 2, dtype=EVENT_DTYPE)
571
+
572
+ out_pos = 0
573
+ exch_pos = 0
574
+ local_pos = 0
575
+ total = len(base_array)
576
+
577
+ while exch_pos < total or local_pos < total:
578
+ exch_row = base_array[sorted_exch_index[exch_pos]] if exch_pos < total else None
579
+ local_row = base_array[sorted_local_index[local_pos]] if local_pos < total else None
580
+
581
+ if exch_row is not None and local_row is not None:
582
+ same_event = (
583
+ exch_row["ev"] == local_row["ev"]
584
+ and exch_row["exch_ts"] == local_row["exch_ts"]
585
+ and exch_row["local_ts"] == local_row["local_ts"]
586
+ and exch_row["px"] == local_row["px"]
587
+ and exch_row["qty"] == local_row["qty"]
588
+ )
589
+ if same_event:
590
+ output[out_pos] = exch_row
591
+ output[out_pos]["ev"] = int(output[out_pos]["ev"]) | EXCH_EVENT | LOCAL_EVENT
592
+ out_pos += 1
593
+ exch_pos += 1
594
+ local_pos += 1
595
+ continue
596
+
597
+ if exch_row["exch_ts"] < local_row["exch_ts"] or (
598
+ exch_row["exch_ts"] == local_row["exch_ts"]
599
+ and exch_row["local_ts"] < local_row["local_ts"]
600
+ ):
601
+ output[out_pos] = exch_row
602
+ output[out_pos]["ev"] = int(output[out_pos]["ev"]) | EXCH_EVENT
603
+ out_pos += 1
604
+ exch_pos += 1
605
+ continue
606
+
607
+ output[out_pos] = local_row
608
+ output[out_pos]["ev"] = int(output[out_pos]["ev"]) | LOCAL_EVENT
609
+ out_pos += 1
610
+ local_pos += 1
611
+ continue
612
+
613
+ if exch_row is not None:
614
+ output[out_pos] = exch_row
615
+ output[out_pos]["ev"] = int(output[out_pos]["ev"]) | EXCH_EVENT
616
+ out_pos += 1
617
+ exch_pos += 1
618
+ continue
619
+
620
+ output[out_pos] = local_row
621
+ output[out_pos]["ev"] = int(output[out_pos]["ev"]) | LOCAL_EVENT
622
+ out_pos += 1
623
+ local_pos += 1
624
+
625
+ return output[:out_pos]