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
backtrader/order.py ADDED
@@ -0,0 +1,1114 @@
1
+ #!/usr/bin/env python
2
+ """Backtrader Order Module.
3
+
4
+ This module provides order data structures and execution tracking.
5
+
6
+ Key Classes:
7
+ OrderExecutionBit: Holds information about a single order execution.
8
+ OrderData: Holds the full order data including creation and execution details.
9
+
10
+ The order system supports:
11
+ - Order creation and execution tracking
12
+ - Partial execution handling
13
+ - Commission calculation
14
+ - PnL calculation for closed positions
15
+ - Position size and price tracking
16
+ """
17
+
18
+ import collections
19
+ import datetime
20
+ import itertools
21
+ from copy import copy
22
+ from typing import Optional
23
+
24
+ from .utils import AutoOrderedDict
25
+ from .utils.py3 import iteritems, range
26
+
27
+
28
+ # Store order execution related information. This information does not determine if the order is fully or partially executed, it only stores the information
29
+ class OrderExecutionBit:
30
+ """
31
+ Intended to hold information about order execution. A "bit" does not
32
+ determine if the order has been fully/partially executed, it just holds
33
+ information.
34
+
35
+ Member Attributes:
36
+
37
+ - dt: datetime (float) execution time
38
+ # Execution time, float
39
+ - size: how much was executed
40
+ # How much was executed
41
+ - price: execution price
42
+ # Execution price
43
+ - closed: how much of the execution closed an existing position
44
+ # How much of existing position was closed
45
+ - opened: how much of the execution opened a new position
46
+ # How much new position was opened
47
+ - openedvalue: market value of the "opened" part
48
+ # Market value of opened position
49
+ - closedvalue: market value of the "closed" part
50
+ # Market value of closed position part
51
+ - closedcomm: commission for the "closed" part
52
+ # Commission for closed position part
53
+ - openedcomm: commission for the "opened" part
54
+ # Commission for opened position part
55
+ - value: market value for the entire bit size
56
+ # Market value of entire position
57
+ - comm: commission for the entire bit execution
58
+ # Commission for entire position
59
+ - pnl: pnl generated by this bit (if something was closed)
60
+ # PnL from closing part of position
61
+ - psize: current open position size
62
+ # Size of already opened position
63
+ - pprice: current open position price
64
+ # Price of already opened position
65
+
66
+ """
67
+
68
+ # Initialize order execution information
69
+ def __init__(
70
+ self,
71
+ dt=None,
72
+ size=0,
73
+ price=0.0,
74
+ closed=0,
75
+ closedvalue=0.0,
76
+ closedcomm=0.0,
77
+ opened=0,
78
+ openedvalue=0.0,
79
+ openedcomm=0.0,
80
+ pnl=0.0,
81
+ psize=0,
82
+ pprice=0.0,
83
+ ):
84
+ """Initialize order execution bit information.
85
+
86
+ Args:
87
+ dt: Execution datetime.
88
+ size: Executed size.
89
+ price: Execution price.
90
+ closed: Size of position closed.
91
+ closedvalue: Value of closed position.
92
+ closedcomm: Commission for closed position.
93
+ opened: Size of new position opened.
94
+ openedvalue: Value of opened position.
95
+ openedcomm: Commission for opened position.
96
+ pnl: Profit/loss from closed position.
97
+ psize: Current position size.
98
+ pprice: Current position price.
99
+ """
100
+ self.dt = dt
101
+ self.size = size
102
+ self.price = price
103
+
104
+ self.closed = closed
105
+ self.opened = opened
106
+ self.closedvalue = closedvalue
107
+ self.openedvalue = openedvalue
108
+ self.closedcomm = closedcomm
109
+ self.openedcomm = openedcomm
110
+
111
+ self.value = closedvalue + openedvalue
112
+ self.comm = closedcomm + openedcomm
113
+ self.pnl = pnl
114
+
115
+ self.psize = psize
116
+ self.pprice = pprice
117
+
118
+ def __repr__(self):
119
+ return (
120
+ f"OrderExecutionBit(size={self.size}, price={self.price}, "
121
+ f"closed={self.closed}, opened={self.opened}, pnl={self.pnl})"
122
+ )
123
+
124
+
125
+ # Store actual order information for creation and execution. When creating, it requests creation; when executing, it produces the final result
126
+ class OrderData:
127
+ """
128
+ Holds actual order data for Creation and Execution.
129
+
130
+ In the case of Creation the request made and in the case of Execution the
131
+ actual outcome.
132
+
133
+ Member Attributes:
134
+
135
+ - exbits : iterable of OrderExecutionBits for this OrderData
136
+ # Serialized order execution information for this order
137
+ - dt: datetime (float) creation/execution time
138
+ # Order creation or execution time, string format
139
+ - size: requested/executed size
140
+ # Creation or execution size
141
+ - price: execution price
142
+ # Execution price. If no price or limit price is given, the order creation
143
+ # or current closing price will be used as reference
144
+ Note: if no price is given and no pricelimite is given, the closing
145
+ price at the time or order creation will be used as reference
146
+ - pricelimit: holds pricelimit for StopLimit (which has trigger first)
147
+ # Limit price for stop limit (triggered first)
148
+ - trailamount: absolute price distance in trailing stops
149
+ # Absolute price distance in trailing stop
150
+ - trailpercent: percentage price distance in trailing stops
151
+ # Percentage distance in trailing stop
152
+ - value: market value for the entire bit size
153
+ # Market value of entire position
154
+ - comm: commission for the entire bit execution
155
+ # Commission for entire position execution
156
+ - pnl: pnl generated by this bit (if something was closed)
157
+ # PnL after closing position
158
+ - margin: margin incurred by the Order (if any)
159
+ # Margin required for order
160
+ - psize: current open position size
161
+ # Current position size
162
+ - pprice: current open position price
163
+ # Current position price
164
+
165
+ """
166
+
167
+ # According to the docs, collections.deque is thread-safe with appends at
168
+ # both ends, there will be no pop (nowhere) and therefore to know which the
169
+ # new exbits are two indices are needed. At time of cloning (__copy__) the
170
+ # indices can be updated to match the previous end, and the new end
171
+ # (len(exbits)
172
+ # Example: start 0, 0 -> islice(exbits, 0, 0) -> []
173
+ # One added -> copy -> updated 0, 1 -> islice(exbits, 0, 1) -> [1 elem]
174
+ # Other added -> copy -> updated 1, 2 -> islice(exbits, 1, 2) -> [1 elem]
175
+ # "add" and "__copy__" happen always in the same thread (with all current
176
+ # implementations) and therefore no append will happen during a copy and
177
+ # the len of the exbits can be queried with no concerns about another
178
+ # thread making an append and with no need for a lock
179
+
180
+ def __init__(
181
+ self,
182
+ dt=None,
183
+ size=0,
184
+ price=0.0,
185
+ pricelimit=0.0,
186
+ remsize=0,
187
+ pclose=0.0,
188
+ trailamount=0.0,
189
+ trailpercent=0.0,
190
+ ):
191
+ """Initialize order data.
192
+
193
+ Args:
194
+ dt: Order datetime.
195
+ size: Order size.
196
+ price: Order price.
197
+ pricelimit: Limit price for stop orders.
198
+ remsize: Remaining size to execute.
199
+ pclose: Previous close price.
200
+ trailamount: Trailing amount for stop orders.
201
+ trailpercent: Trailing percent for stop orders.
202
+ """
203
+ self.pclose = pclose
204
+ self.exbits: collections.deque = collections.deque() # for historical purposes
205
+ self.p1, self.p2 = 0, 0 # indices to pending notifications
206
+
207
+ self.dt = dt
208
+ self.size = size
209
+ self.remsize = remsize
210
+ self.price = price
211
+ self.pricelimit = pricelimit
212
+ self.trailamount = trailamount
213
+ self.trailpercent = trailpercent
214
+ # If no limit price, use the price as limit price
215
+ if not pricelimit:
216
+ # if no pricelimit is given, use the given price
217
+ self.pricelimit = self.price
218
+ # If there is limit price but no price, price equals limit price
219
+ if pricelimit and not price:
220
+ # price must always be set if pricelimit is set ...
221
+ self.price = pricelimit
222
+ # Limit price
223
+ self.plimit = pricelimit
224
+
225
+ self.value = 0.0
226
+ self.comm = 0.0
227
+ self.margin = None
228
+ self.pnl = 0.0
229
+
230
+ self.psize = 0
231
+ self.pprice = 0
232
+
233
+ # Set plimit property
234
+
235
+ def _getplimit(self):
236
+ return self._plimit
237
+
238
+ def _setplimit(self, val):
239
+ self._plimit = val
240
+
241
+ plimit = property(_getplimit, _setplimit)
242
+
243
+ # Return length of execution information
244
+ def __len__(self):
245
+ return len(self.exbits)
246
+
247
+ # Get execution information value
248
+ def __getitem__(self, key):
249
+ return self.exbits[key]
250
+
251
+ # Add execution information
252
+ def add(
253
+ self,
254
+ dt,
255
+ size,
256
+ price,
257
+ closed=0,
258
+ closedvalue=0.0,
259
+ closedcomm=0.0,
260
+ opened=0,
261
+ openedvalue=0.0,
262
+ openedcomm=0.0,
263
+ pnl=0.0,
264
+ psize=0,
265
+ pprice=0.0,
266
+ ):
267
+ """Add execution information to this order.
268
+
269
+ Args:
270
+ dt: Execution datetime.
271
+ size: Executed size.
272
+ price: Execution price.
273
+ closed: Size of position closed.
274
+ closedvalue: Value of closed position.
275
+ closedcomm: Commission for closed position.
276
+ opened: Size of new position opened.
277
+ openedvalue: Value of opened position.
278
+ openedcomm: Commission for opened position.
279
+ pnl: Profit/loss from closed position.
280
+ psize: Current position size.
281
+ pprice: Current position price.
282
+ """
283
+ self.addbit(
284
+ OrderExecutionBit(
285
+ dt,
286
+ size,
287
+ price,
288
+ closed,
289
+ closedvalue,
290
+ closedcomm,
291
+ opened,
292
+ openedvalue,
293
+ openedcomm,
294
+ pnl,
295
+ psize,
296
+ pprice,
297
+ )
298
+ )
299
+
300
+ # Adjust current attributes based on order execution
301
+ def addbit(self, exbit):
302
+ """Store an execution bit and recalculate order values.
303
+
304
+ Args:
305
+ exbit: OrderExecutionBit to add.
306
+ """
307
+ # Stores an ExecutionBit and recalculates own values from ExBit
308
+ self.exbits.append(exbit)
309
+
310
+ self.remsize -= exbit.size
311
+
312
+ self.dt = exbit.dt
313
+ oldvalue = self.size * self.price
314
+ newvalue = exbit.size * exbit.price
315
+ self.size += exbit.size
316
+ self.price = (oldvalue + newvalue) / self.size if self.size else 0.0
317
+ self.value += exbit.value
318
+ self.comm += exbit.comm
319
+ self.pnl += exbit.pnl
320
+ self.psize = exbit.psize
321
+ self.pprice = exbit.pprice
322
+
323
+ # Get current pending execution information
324
+ def getpending(self):
325
+ """Get list of pending execution bits.
326
+
327
+ Returns:
328
+ list: List of pending OrderExecutionBit objects.
329
+ """
330
+ return list(self.iterpending())
331
+
332
+ # Slice order pending execution information, if p1 and p2 both equal 0, returns empty
333
+ def iterpending(self):
334
+ """Iterate over pending execution bits.
335
+
336
+ Returns:
337
+ iterator: Iterator over pending OrderExecutionBit objects.
338
+ """
339
+ return itertools.islice(self.exbits, self.p1, self.p2)
340
+
341
+ # Mark which pending order execution information
342
+ def markpending(self):
343
+ """Mark current execution bits as pending.
344
+
345
+ Rebuilds the indices to mark which exbits are pending in clone.
346
+ """
347
+ # rebuild the indices to mark which exbits are pending in clone
348
+ self.p1, self.p2 = self.p2, len(self.exbits)
349
+
350
+ # Clone the object
351
+ def clone(self):
352
+ """Clone the OrderData object.
353
+
354
+ Returns:
355
+ OrderData: A cloned copy with marked pending bits.
356
+ """
357
+ self.markpending()
358
+ obj = copy(self)
359
+ return obj
360
+
361
+
362
+ # Simple parameter container to replace metaclass functionality
363
+ class OrderParams:
364
+ """Simple parameter container for Order classes.
365
+
366
+ Stores order parameters like owner, data, size, price, execution type, etc.
367
+ """
368
+
369
+ def __init__(self, **kwargs):
370
+ """Initialize order parameters with defaults.
371
+
372
+ Args:
373
+ **kwargs: Keyword arguments to override default parameters.
374
+
375
+ Raises:
376
+ AttributeError: If an invalid parameter is provided.
377
+ """
378
+ # Default parameters
379
+ defaults = {
380
+ "owner": None,
381
+ "data": None,
382
+ "size": None,
383
+ "price": None,
384
+ "pricelimit": None,
385
+ "exectype": None,
386
+ "valid": None,
387
+ "tradeid": 0,
388
+ "oco": None,
389
+ "trailamount": None,
390
+ "trailpercent": None,
391
+ "parent": None,
392
+ "transmit": True,
393
+ "simulated": False,
394
+ "histnotify": False,
395
+ }
396
+
397
+ # Set defaults first
398
+ for key, value in defaults.items():
399
+ setattr(self, key, value)
400
+
401
+ # Override with provided kwargs
402
+ for key, value in kwargs.items():
403
+ if hasattr(self, key):
404
+ setattr(self, key, value)
405
+ else:
406
+ raise AttributeError(f"Invalid parameter: {key}")
407
+
408
+
409
+ class OrderBase:
410
+ """Base class for order objects.
411
+
412
+ Provides the foundation for all order types with common attributes
413
+ and methods for order tracking, status management, and execution.
414
+
415
+ Class Attributes:
416
+ DAY: Constant for day order identification.
417
+ Market, Close, Limit, Stop, StopLimit, StopTrail, StopTrailLimit: Order execution types.
418
+ Buy, Sell: Order direction types.
419
+ Created, Submitted, Accepted, Partial, Completed, Canceled, Expired, Margin, Rejected: Order status codes.
420
+
421
+ Attributes:
422
+ ref: Unique order reference number.
423
+ broker: Broker instance handling this order.
424
+ p: OrderParams instance containing order parameters.
425
+ """
426
+
427
+ # Basic parameters for orders - removed metaclass usage
428
+ # DAY currently represents empty time delta
429
+ DAY = datetime.timedelta() # constant for DAY order identification
430
+
431
+ # Time Restrictions for orders
432
+ # Time restrictions for orders
433
+ T_Close, T_Day, T_Date, T_None = range(4)
434
+
435
+ # Volume Restrictions for orders
436
+ # Volume restrictions for orders
437
+ V_None = range(1)
438
+
439
+ # Different order types, represented by different numbers
440
+ Market, Close, Limit, Stop, StopLimit, StopTrail, StopTrailLimit, Historical = range(8)
441
+ ExecTypes = [
442
+ "Market",
443
+ "Close",
444
+ "Limit",
445
+ "Stop",
446
+ "StopLimit",
447
+ "StopTrail",
448
+ "StopTrailLimit",
449
+ "Historical",
450
+ ]
451
+ # Order direction types
452
+ OrdTypes = ["Buy", "Sell"]
453
+ Buy, Sell = range(2)
454
+ # Different order statuses
455
+ Created, Submitted, Accepted, Partial, Completed, Canceled, Expired, Margin, Rejected = range(9)
456
+
457
+ Cancelled = Canceled # alias
458
+
459
+ Status = [
460
+ "Created",
461
+ "Submitted",
462
+ "Accepted",
463
+ "Partial",
464
+ "Completed",
465
+ "Canceled",
466
+ "Expired",
467
+ "Margin",
468
+ "Rejected",
469
+ ]
470
+ # Add a number for each order
471
+ refbasis = itertools.count(1) # for a unique identifier per order
472
+
473
+ # Set/get plimit property
474
+ def _getplimit(self):
475
+ return self._plimit
476
+
477
+ def _setplimit(self, val):
478
+ self._plimit = val
479
+
480
+ plimit = property(_getplimit, _setplimit)
481
+
482
+ # Get order attribute - modified to work with OrderParams
483
+ def __getattr__(self, name):
484
+ # Return attr from params if not found in order
485
+ # PERFORMANCE OPTIMIZATION: Use try/except instead of hasattr
486
+ # Called 1.65M+ times, reduce attribute lookups
487
+ if name == "p": # Avoid recursion when checking for 'p' itself
488
+ raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
489
+ try:
490
+ p = object.__getattribute__(self, "p")
491
+ return getattr(p, name)
492
+ except AttributeError:
493
+ # ``copy.copy`` legitimately probes ``__setstate__`` here for
494
+ # every order clone. This is an expected protocol miss, not a
495
+ # recoverable runtime failure, so keep the compatibility fallback
496
+ # silent on the hot path.
497
+ raise AttributeError(
498
+ f"'{self.__class__.__name__}' object has no attribute '{name}'"
499
+ ) from None
500
+
501
+ # Set order attribute - modified to work with OrderParams
502
+ def __setattr__(self, name, value):
503
+ # Check if we have params and the name exists in params
504
+ # Use object.__getattribute__ to avoid recursion
505
+ try:
506
+ p = object.__getattribute__(self, "p")
507
+ if hasattr(p, name):
508
+ setattr(p, name, value)
509
+ return
510
+ except AttributeError:
511
+ # ``p`` is deliberately absent during early construction.
512
+ # Logging that expected state once per new order adds avoidable
513
+ # work before the parameter object exists.
514
+ pass
515
+
516
+ super().__setattr__(name, value)
517
+
518
+ # Content displayed when printing order
519
+ def __str__(self):
520
+ tojoin = []
521
+ tojoin.append(f"Ref: {self.ref}")
522
+ tojoin.append(f"OrdType: {self.ordtype}")
523
+ tojoin.append(f"OrdType: {self.ordtypename()}")
524
+ tojoin.append(f"Status: {self.status}")
525
+ tojoin.append(f"Status: {self.getstatusname()}")
526
+ tojoin.append(f"Size: {self.size}")
527
+ tojoin.append(f"Price: {self.price}")
528
+ tojoin.append(f"Price Limit: {self.pricelimit}")
529
+ tojoin.append(f"TrailAmount: {self.trailamount}")
530
+ tojoin.append(f"TrailPercent: {self.trailpercent}")
531
+ tojoin.append(f"ExecType: {self.exectype}")
532
+ tojoin.append(f"ExecType: {self.getordername()}")
533
+ tojoin.append(f"CommInfo: {self.comminfo}")
534
+ tojoin.append(f"End of Session: {self.dteos}")
535
+ tojoin.append(f"Info: {self.info}")
536
+ tojoin.append(f"Broker: {self.broker}")
537
+ tojoin.append(f"Alive: {self.alive()}")
538
+
539
+ return "\n".join(tojoin)
540
+
541
+ # Initialize class - modified to accept kwargs and create params manually
542
+ def __init__(self, **kwargs):
543
+ """Initialize the order base instance.
544
+
545
+ Args:
546
+ **kwargs: Order parameters (owner, data, size, price, etc.).
547
+ """
548
+ # Create params object manually instead of using metaclass
549
+ self.p = OrderParams(**kwargs)
550
+ # Create convenient direct access to params - alias for backward compatibility
551
+ self.params = self.p
552
+
553
+ # Increment a number each time an instance is created
554
+ self.plen = None
555
+ self.ref = next(self.refbasis)
556
+ # broker defaults to None
557
+ self.broker = None
558
+ # order info information
559
+ self.info = AutoOrderedDict()
560
+ # commission defaults to None
561
+ self.comminfo = None
562
+ # triggered defaults to None
563
+ self.triggered = False
564
+ # If self.parent is None, self._active is True, otherwise it's None
565
+ self._active = self.parent is None
566
+ # Order status, when order initializes, defaults to Created
567
+ self.status = OrderBase.Created
568
+ # Set plimit property value
569
+ self.plimit = self.p.pricelimit # alias via property
570
+ # If order execution type is None, default is Market order
571
+ if self.exectype is None:
572
+ self.exectype = OrderBase.Market
573
+ # If order is not a buy order, order size becomes negative
574
+ if not self.isbuy():
575
+ self.size = -self.size
576
+
577
+ # Set a reference price if price is not set using the close price
578
+ pclose = self.data.close[0] if not self.p.simulated else self.price
579
+ price = pclose if self.price is None and self.pricelimit is None else self.price
580
+ # If not simulated, order creation time equals current data time, otherwise it's 0
581
+ dcreated = self.data.datetime[0] if not self.p.simulated else 0.0
582
+ # Order creation
583
+ self.created = OrderData(
584
+ dt=dcreated,
585
+ size=self.size,
586
+ price=price,
587
+ pricelimit=self.pricelimit,
588
+ pclose=pclose,
589
+ trailamount=self.trailamount,
590
+ trailpercent=self.trailpercent,
591
+ )
592
+
593
+ # Adjust price in case a trailing limit is wished
594
+ # If execution type is trailing stop, price needs adjustment. Limit offset equals created price minus created limit price
595
+ # Price equals order creation price, reset created order price to infinity for buy orders, negative infinity for sell orders
596
+ # Then adjust price; if not trailing stop type, limit offset is 0
597
+ if self.exectype in [OrderBase.StopTrail, OrderBase.StopTrailLimit]:
598
+ self._limitoffset = self.created.price - self.created.pricelimit
599
+ price = self.created.price
600
+ self.created.price = float("inf" * self.isbuy() or "-inf")
601
+ self.trailadjust(price)
602
+ else:
603
+ self._limitoffset = 0.0
604
+ # Order execution
605
+ self.executed = OrderData(remsize=self.size)
606
+ # Position set to 0
607
+ self.position = 0
608
+ # Next is to determine order validity period
609
+ # If validity parameter is a date format
610
+ if isinstance(self.valid, datetime.date):
611
+ # comparison will later be done against the raw datetime[0] value
612
+ # Convert date format to number
613
+ self.valid = self.data.date2num(self.valid)
614
+ # If validity parameter is a time delta format, if time delta is 0, valid for the day, otherwise current time plus time delta
615
+ # Then convert obtained validity to number
616
+ elif isinstance(self.valid, datetime.timedelta):
617
+ # offset with regards to now ... get utcnow + offset
618
+ # when reading with date2num ... it will be automatically localized
619
+ if self.valid == self.DAY:
620
+ valid = datetime.datetime.combine(
621
+ self.data.datetime.date(), datetime.time(23, 59, 59, 9999)
622
+ )
623
+ else:
624
+ valid = self.data.datetime.datetime() + self.valid
625
+
626
+ self.valid = self.data.date2num(valid)
627
+ # If validity is not None, if not 0, valid for the day, if 0, currently valid
628
+ elif self.valid is not None:
629
+ if not self.valid: # avoid comparing None and 0
630
+ valid = datetime.datetime.combine(
631
+ self.data.datetime.date(), datetime.time(23, 59, 59, 9999)
632
+ )
633
+ else: # assume float
634
+ valid = self.data.datetime[0] + self.valid
635
+ # If not simulated, get dteos, if simulated, dteos is 0
636
+ # dteos: provisional end-of-session datetime, used by broker for order expiry checks
637
+ if not self.p.simulated:
638
+ # provisional end-of-session
639
+ # get next session end
640
+ dtime = self.data.datetime.datetime(0)
641
+ session = self.data.p.sessionend
642
+ dteos = dtime.replace(
643
+ hour=session.hour,
644
+ minute=session.minute,
645
+ second=session.second,
646
+ microsecond=session.microsecond,
647
+ )
648
+
649
+ if dteos < dtime:
650
+ # eos before current time ... no ... must be at least next day
651
+ dteos += datetime.timedelta(days=1)
652
+
653
+ self.dteos = self.data.date2num(dteos)
654
+ else:
655
+ self.dteos = 0.0
656
+
657
+ # Clone the order itself
658
+ def clone(self):
659
+ """Clone the order.
660
+
661
+ Returns:
662
+ OrderBase: A cloned copy with cloned executed OrderData.
663
+ """
664
+ # status, triggered and executed are the only moving parts in order
665
+ # status and triggered are covered by copy
666
+ # executed has to be replaced with an intelligent clone of itself
667
+ obj = copy(self)
668
+ obj.executed = self.executed.clone()
669
+ return obj # status could change in next to completed
670
+
671
+ @property
672
+ def position_side(self):
673
+ """Read-only alias for order.info.position_side."""
674
+ return getattr(self.info, "position_side", None)
675
+
676
+ @property
677
+ def offset(self):
678
+ """Read-only alias for order.info.offset."""
679
+ return getattr(self.info, "offset", None)
680
+
681
+ # Get order status name
682
+ def getstatusname(self, status=None):
683
+ """Returns the name for a given status or the one of the order"""
684
+ idx = self.status if status is None else status
685
+ try:
686
+ return self.Status[idx]
687
+ except (IndexError, TypeError):
688
+ return f"Unknown({idx})"
689
+
690
+ # Get order name
691
+ def getordername(self, exectype=None):
692
+ """Returns the name for a given exectype or the one of the order"""
693
+ idx = self.exectype if exectype is None else exectype
694
+ try:
695
+ return self.ExecTypes[idx]
696
+ except (IndexError, TypeError):
697
+ return f"Unknown({idx})"
698
+
699
+ @classmethod
700
+ def ExecType(cls, exectype):
701
+ """Get the execution type constant from the class.
702
+
703
+ Args:
704
+ exectype: String name of the execution type.
705
+
706
+ Returns:
707
+ int: The execution type constant.
708
+ """
709
+ return getattr(cls, exectype)
710
+
711
+ # Get order type name
712
+ def ordtypename(self, ordtype=None):
713
+ """Returns the name for a given ordtype or the one of the order"""
714
+ return self.OrdTypes[self.ordtype if ordtype is None else ordtype]
715
+
716
+ # Get active status
717
+ def active(self):
718
+ """Check if the order is active.
719
+
720
+ Returns:
721
+ bool: True if order is active, False otherwise.
722
+ """
723
+ return self._active
724
+
725
+ # Activate order
726
+ def activate(self):
727
+ """Activate the order."""
728
+ self._active = True
729
+
730
+ # Frozenset for O(1) alive status lookup
731
+ _ALIVE_STATUSES = frozenset(range(4)) # Created, Submitted, Accepted, Partial
732
+
733
+ # Order is alive if it's in Created, Submitted, Partial, or Accepted status
734
+ def alive(self):
735
+ """Returns True if the order is in a status in which it can still be
736
+ executed
737
+ """
738
+ return self.status in self._ALIVE_STATUSES
739
+
740
+ # Add commission related information
741
+ def addcomminfo(self, comminfo):
742
+ """Stores a CommInfo scheme associated with the asset"""
743
+ self.comminfo = comminfo
744
+
745
+ # Add information
746
+ def addinfo(self, **kwargs):
747
+ """Add the keys, values of kwargs to the internal info dictionary to
748
+ hold custom information in the order
749
+ """
750
+ for key, val in iteritems(kwargs):
751
+ self.info[key] = val
752
+
753
+ # Check if two orders are equal
754
+ def __eq__(self, other):
755
+ return other is not None and self.ref == other.ref
756
+
757
+ # Check if two orders are not equal
758
+ def __ne__(self, other):
759
+ return other is None or self.ref != other.ref
760
+
761
+ # Order ref is immutable, so hash based on ref is safe
762
+ def __hash__(self):
763
+ return hash(self.ref)
764
+
765
+ # Check if current order is a buy order
766
+ def isbuy(self):
767
+ """Returns True if the order is a Buy order"""
768
+ return self.ordtype == OrderBase.Buy
769
+
770
+ # Check if current order is a sell order
771
+ def issell(self):
772
+ """Returns True if the order is a Sell order"""
773
+ return self.ordtype == OrderBase.Sell
774
+
775
+ # Set specific position size for order
776
+ def setposition(self, position):
777
+ """Receives the current position for the asset and stores it"""
778
+ self.position = position
779
+
780
+ # Submit order to broker
781
+ def submit(self, broker=None):
782
+ """Marks an order as submitted and stores the broker to which it was
783
+ submitted"""
784
+ self.status = OrderBase.Submitted
785
+ self.broker = broker
786
+ self.plen = len(self.data)
787
+
788
+ # Accept order
789
+ def accept(self, broker=None):
790
+ """Marks an order as accepted"""
791
+ self.status = OrderBase.Accepted
792
+ self.broker = broker
793
+
794
+ # Broker status, if broker is not None or 0, try to get order status from broker, if broker is None, directly return order status
795
+ def brokerstatus(self):
796
+ """Tries to retrieve the status from the broker in which the order is.
797
+
798
+ Defaults to last known status if no broker is associated"""
799
+ if self.broker:
800
+ return self.broker.orderstatus(self)
801
+
802
+ return self.status
803
+
804
+ # Reject order, if already rejected return False, otherwise set order status and rejection execution time, broker, then return True
805
+ def reject(self, broker=None):
806
+ """Marks an order as rejected"""
807
+ if self.status == OrderBase.Rejected:
808
+ return False
809
+
810
+ self.status = OrderBase.Rejected
811
+ # self.executed.dt = self.data.datetime[0]
812
+ self.broker = broker
813
+ if not self.p.simulated:
814
+ self.executed.dt = self.data.datetime[0]
815
+ return True
816
+
817
+ # Cancel order
818
+ def cancel(self):
819
+ """Marks an order as cancelled"""
820
+ self.status = OrderBase.Canceled
821
+ # self.executed.dt = self.data.datetime[0]
822
+ if not self.p.simulated:
823
+ self.executed.dt = self.data.datetime[0]
824
+
825
+ # Insufficient margin, add margin
826
+ def margin(self):
827
+ """Marks an order as having met a margin call"""
828
+ self.status = OrderBase.Margin
829
+ # self.executed.dt = self.data.datetime[0]
830
+ if not self.p.simulated:
831
+ self.executed.dt = self.data.datetime[0]
832
+
833
+ # Complete
834
+ def completed(self):
835
+ """Marks an order as completely filled"""
836
+ self.status = OrderBase.Completed
837
+
838
+ # Partial execution
839
+ def partial(self):
840
+ """Marks an order as partially filled"""
841
+ self.status = OrderBase.Partial
842
+
843
+ # Execute order
844
+ def execute(
845
+ self,
846
+ dt,
847
+ size,
848
+ price,
849
+ closed,
850
+ closedvalue,
851
+ closedcomm,
852
+ opened,
853
+ openedvalue,
854
+ openedcomm,
855
+ margin,
856
+ pnl,
857
+ psize,
858
+ pprice,
859
+ ):
860
+ """Receives data execution input and stores it"""
861
+ if not size:
862
+ return
863
+
864
+ self.executed.add(
865
+ dt,
866
+ size,
867
+ price,
868
+ closed,
869
+ closedvalue,
870
+ closedcomm,
871
+ opened,
872
+ openedvalue,
873
+ openedcomm,
874
+ pnl,
875
+ psize,
876
+ pprice,
877
+ )
878
+
879
+ self.executed.margin = margin
880
+
881
+ # Order expiration
882
+ def expire(self):
883
+ """Marks an order as expired. Returns True if it worked"""
884
+ self.status = OrderBase.Expired
885
+ return True
886
+
887
+ # Trail price adjustment
888
+ def trailadjust(self, price):
889
+ """Adjust trailing stop price.
890
+
891
+ Args:
892
+ price: Current price for trailing calculation.
893
+
894
+ Note:
895
+ Generic interface - override in subclasses for specific behavior.
896
+ """
897
+ # generic interface
898
+
899
+
900
+ # Modified Order class to work without metaclass
901
+ class Order(OrderBase):
902
+ """Order class for buy/sell orders.
903
+
904
+ Extends OrderBase with order type (buy/sell) and session end time
905
+ handling. This is the main order class used for creating and
906
+ managing trading orders.
907
+
908
+ Attributes:
909
+ ordtype: Order type (Buy or Sell).
910
+ dteos: Date/time of end of session for order validity.
911
+ """
912
+
913
+ # Above is processing of OrderBase, below is processing of Order, Order inherits from OrderBase
914
+ # Order class mainly adds dteos, ordtype and other information, also rewrites some functions, adds ordtype, a tracking price
915
+ # ordtype variable determines whether this order is a buy order or sell order, not set by default
916
+ ordtype: Optional[int] = None
917
+
918
+ # Override initialization function, add processing for ordtype and dteos
919
+ def __init__(self, **kwargs):
920
+ """Initialize the order instance.
921
+
922
+ Args:
923
+ **kwargs: Order parameters (owner, data, size, price, etc.).
924
+ """
925
+ super().__init__(**kwargs)
926
+
927
+ # For Order, additional operations on dteos are needed
928
+ # dteos represents the end time of this session
929
+ # The code logic below is:
930
+ # dteos == 0.0 represents day order, i.e., order valid for the day, in this case dteos is the session end time of the day
931
+ # dteos >= self.data.datetime[0] means the order's validity period is greater than the current data time, no need to modify dteos
932
+ # In other cases, set dteos to 0, making it a day order
933
+ if self.dteos == 0.0:
934
+ # day order -> till session end if not changed before
935
+ pass
936
+ elif self.dteos >= self.data.datetime[0]:
937
+ # if dteos is in future -> inform order it's a GTD (good till date)
938
+ pass
939
+ else:
940
+ # If current time exceeds dteos, set dteos to 0.0
941
+ # Expiration date less than current time -> becomes day order
942
+ self.dteos = 0.0
943
+
944
+ # Execute this order, many parameters need to be passed during execution
945
+ def execute(
946
+ self,
947
+ dt,
948
+ size,
949
+ price,
950
+ closed,
951
+ closedvalue,
952
+ closedcomm,
953
+ opened,
954
+ openedvalue,
955
+ openedcomm,
956
+ margin,
957
+ pnl,
958
+ psize,
959
+ pprice,
960
+ ):
961
+ """Execute the order with given parameters.
962
+
963
+ Args:
964
+ dt: Execution datetime.
965
+ size: Executed size.
966
+ price: Execution price.
967
+ closed: Size of position closed.
968
+ closedvalue: Value of closed position.
969
+ closedcomm: Commission for closed position.
970
+ opened: Size of new position opened.
971
+ openedvalue: Value of opened position.
972
+ openedcomm: Commission for opened position.
973
+ margin: Margin required for the order.
974
+ pnl: Profit/loss from closed position.
975
+ psize: Current position size.
976
+ pprice: Current position price.
977
+ """
978
+ self.executed.add(
979
+ dt,
980
+ size,
981
+ price,
982
+ closed,
983
+ closedvalue,
984
+ closedcomm,
985
+ opened,
986
+ openedvalue,
987
+ openedcomm,
988
+ pnl,
989
+ psize,
990
+ pprice,
991
+ )
992
+
993
+ if margin is not None:
994
+ self.executed.margin = margin
995
+
996
+ if self.executed.remsize:
997
+ self.status = OrderBase.Partial
998
+ else:
999
+ self.status = OrderBase.Completed
1000
+
1001
+ # Order expiration
1002
+ def expire(self):
1003
+ """Check if order should be expired
1004
+
1005
+ Returns:
1006
+ True: If order has expired
1007
+ False: If order has not expired
1008
+ """
1009
+ # Market orders don't expire, will always be executed
1010
+ if self.exectype == Order.Market:
1011
+ return False
1012
+
1013
+ # Check if order exceeds validity period
1014
+ if self.valid and self.data.datetime[0] > self.valid:
1015
+ self.status = Order.Expired
1016
+ self.executed.dt = self.data.datetime[0]
1017
+ return True
1018
+
1019
+ return False
1020
+
1021
+ # Trail adjust price, trail adjust price is for trailing stop orders. Trailing stop order is also a moving stop order,
1022
+ # the moving distance can be represented by absolute value or percentage. This function is mainly to calculate
1023
+ # the price after trailing stop order adjustment
1024
+ def trailadjust(self, price):
1025
+ """Adjust trailing stop order price.
1026
+
1027
+ Args:
1028
+ price: Current market price for trailing calculation.
1029
+
1030
+ For buy orders: stop price moves up as price increases.
1031
+ For sell orders: stop price moves down as price decreases.
1032
+ """
1033
+ # If moving amount, price adjustment amount is the moving amount; if moving percentage,
1034
+ # price adjustment amount is price multiplied by percentage, otherwise price adjustment amount is 0
1035
+ if self.trailamount:
1036
+ adjsize = self.trailamount
1037
+ elif self.trailpercent:
1038
+ adjsize = price * self.trailpercent
1039
+ else:
1040
+ adjsize = 0.0
1041
+
1042
+ # CRITICAL FIX: BUY stop is ABOVE market (+adjsize), SELL stop is BELOW market (-adjsize)
1043
+ # Original formula was backwards: (1 - 2*isbuy) gave -1 for buy, +1 for sell
1044
+ # Correct formula: (2*isbuy - 1) gives +1 for buy, -1 for sell
1045
+ price_new = price + adjsize * (2 * self.isbuy() - 1)
1046
+
1047
+ # If price_new surpasses self.created.price -> readjust
1048
+ # If new price exceeds originally created price, readjust.
1049
+ # For buy orders, if new price is less than created price, use this new price
1050
+ # For sell orders, if new price is greater than created price, use this new price
1051
+ if price_new != self.created.price:
1052
+ if (
1053
+ self.isbuy()
1054
+ and price_new < self.created.price
1055
+ or self.issell()
1056
+ and price_new > self.created.price
1057
+ ):
1058
+ self.created.price = price_new
1059
+
1060
+ # For both trailing stop types, limitprice also needs adjustment
1061
+ if self.exectype == OrderBase.StopTrailLimit:
1062
+ self.created.pricelimit = self.created.price + self._limitoffset
1063
+
1064
+
1065
+ # Buy order
1066
+ class BuyOrder(Order):
1067
+ """Buy order class.
1068
+
1069
+ Represents a buy order with ordtype set to Order.Buy.
1070
+ """
1071
+
1072
+ ordtype = Order.Buy
1073
+
1074
+
1075
+ # Stop buy order
1076
+ class StopBuyOrder(BuyOrder):
1077
+ """Stop buy order class.
1078
+
1079
+ Used for buy orders that trigger when price crosses a threshold.
1080
+ """
1081
+
1082
+
1083
+ # Create stop limit buy order
1084
+ class StopLimitBuyOrder(BuyOrder):
1085
+ """Stop limit buy order class.
1086
+
1087
+ Used for buy orders that become limit orders after stop price is triggered.
1088
+ """
1089
+
1090
+
1091
+ # Create sell order
1092
+ class SellOrder(Order):
1093
+ """Sell order class.
1094
+
1095
+ Represents a sell order with ordtype set to Order.Sell.
1096
+ """
1097
+
1098
+ ordtype = Order.Sell
1099
+
1100
+
1101
+ # Create stop sell order
1102
+ class StopSellOrder(SellOrder):
1103
+ """Stop sell order class.
1104
+
1105
+ Used for sell orders that trigger when price crosses a threshold.
1106
+ """
1107
+
1108
+
1109
+ # Create stop limit sell order
1110
+ class StopLimitSellOrder(SellOrder):
1111
+ """Stop limit sell order class.
1112
+
1113
+ Used for sell orders that become limit orders after stop price is triggered.
1114
+ """