bbstrader 0.3.0__py3-none-any.whl → 0.3.1__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.

Potentially problematic release.


This version of bbstrader might be problematic. Click here for more details.

@@ -1,7 +1,8 @@
1
1
  import multiprocessing as mp
2
+ import sys
2
3
  import time
3
4
  from datetime import date, datetime
4
- from typing import Dict, List, Literal, Optional
5
+ from typing import Callable, Dict, List, Literal, Optional
5
6
 
6
7
  import pandas as pd
7
8
  from loguru import logger as log
@@ -88,7 +89,7 @@ NON_EXEC_RETCODES = {
88
89
  log.add(
89
90
  f"{BBSTRADER_DIR}/logs/execution.log",
90
91
  enqueue=True,
91
- level="INFO",
92
+ level="DEBUG",
92
93
  format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {name} | {message}",
93
94
  )
94
95
 
@@ -171,10 +172,11 @@ class Mt5ExecutionEngine:
171
172
  self,
172
173
  symbol_list: List[str],
173
174
  trades_instances: Dict[str, Trade],
174
- strategy_cls: Strategy,
175
+ strategy_cls: Strategy | MT5Strategy,
175
176
  /,
176
177
  mm: bool = True,
177
178
  auto_trade: bool = True,
179
+ prompt_callback: Callable = None,
178
180
  optimizer: str = "equal",
179
181
  trail: bool = True,
180
182
  stop_trail: Optional[int] = None,
@@ -201,6 +203,8 @@ class Mt5ExecutionEngine:
201
203
  auto_trade : If set to true, when signal are generated by the strategy class,
202
204
  the Execution engine will automaticaly open position in other whise it will prompt
203
205
  the user for confimation.
206
+ prompt_callback : Callback function to prompt the user for confirmation.
207
+ This is useful when integrating with GUI applications.
204
208
  show_positions_orders : Print open positions and orders. Defaults to False.
205
209
  iter_time : Interval to check for signals and `mm`. Defaults to 5.
206
210
  use_trade_time : Open trades after the time is completed. Defaults to True.
@@ -244,6 +248,7 @@ class Mt5ExecutionEngine:
244
248
  self.strategy_cls = strategy_cls
245
249
  self.mm = mm
246
250
  self.auto_trade = auto_trade
251
+ self.prompt_callback = prompt_callback
247
252
  self.optimizer = optimizer
248
253
  self.trail = trail
249
254
  self.stop_trail = stop_trail
@@ -267,6 +272,7 @@ class Mt5ExecutionEngine:
267
272
 
268
273
  self._initialize_engine(**kwargs)
269
274
  self.strategy = self._init_strategy(**kwargs)
275
+ self._running = True
270
276
 
271
277
  def __repr__(self):
272
278
  trades = self.trades_instances.keys()
@@ -308,7 +314,7 @@ class Mt5ExecutionEngine:
308
314
  def _print_exc(self, msg: str, e: Exception):
309
315
  if isinstance(e, KeyboardInterrupt):
310
316
  logger.info("Stopping the Execution Engine ...")
311
- quit()
317
+ sys.exit(0)
312
318
  if self.debug_mode:
313
319
  raise ValueError(msg).with_traceback(e.__traceback__)
314
320
  else:
@@ -332,10 +338,10 @@ class Mt5ExecutionEngine:
332
338
  expert_ids = [expert_ids]
333
339
  return expert_ids
334
340
 
335
- def _init_strategy(self, **kwargs):
341
+ def _init_strategy(self, **kwargs) -> Strategy | MT5Strategy:
336
342
  try:
337
343
  check_mt5_connection(**kwargs)
338
- strategy: MT5Strategy = self.strategy_cls(
344
+ strategy = self.strategy_cls(
339
345
  symbol_list=self.symbols, mode=TradingMode.LIVE, **kwargs
340
346
  )
341
347
  except Exception as e:
@@ -367,21 +373,21 @@ class Mt5ExecutionEngine:
367
373
  ).format(**common_data)
368
374
 
369
375
  sigmsg = (
370
- "SIGNAL={signal},\n"
371
- "SYMBOL={symbol},\n"
372
- "TYPE={symbol_type},\n"
373
- "DESCRIPTION={description},\n"
374
- "PRICE={price},\n"
375
- "STOPLIMIT={stoplimit},\n"
376
- "STRATEGY={strategy},\n"
377
- "TIMEFRAME={timeframe},\n"
378
- "BROKER={broker},\n"
376
+ "SIGNAL={signal}\n"
377
+ "SYMBOL={symbol}\n"
378
+ "TYPE={symbol_type}\n"
379
+ "DESCRIPTION={description}\n"
380
+ "PRICE={price}\n"
381
+ "STOPLIMIT={stoplimit}\n"
382
+ "STRATEGY={strategy}\n"
383
+ "TIMEFRAME={timeframe}\n"
384
+ "BROKER={broker}\n"
379
385
  "TIMESTAMP={timestamp}"
380
386
  ).format(
381
387
  **common_data,
382
388
  symbol_type=account.get_symbol_type(symbol).value,
383
- description=symbol_info.description,
384
- price=price,
389
+ description=symbol_info.description if symbol_info else "N/A",
390
+ price=price if price else "MARKET",
385
391
  stoplimit=stoplimit,
386
392
  broker=account.broker.name,
387
393
  timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
@@ -520,7 +526,7 @@ class Mt5ExecutionEngine:
520
526
  def _daily_end_checks(self, today, closing, sessionmsg):
521
527
  self.strategy.perform_period_end_checks()
522
528
  if self.period_end_action == "break" and closing:
523
- exit(0)
529
+ sys.exit(0)
524
530
  elif self.period_end_action == "sleep" and today != FRIDAY or not closing:
525
531
  self._sleep_over_night(sessionmsg)
526
532
  elif self.period_end_action == "sleep" and today == FRIDAY:
@@ -532,7 +538,7 @@ class Mt5ExecutionEngine:
532
538
  elif today == FRIDAY:
533
539
  self.strategy.perform_period_end_checks()
534
540
  if self.period_end_action == "break" and closing:
535
- exit(0)
541
+ sys.exit(0)
536
542
  elif self.period_end_action == "sleep" or not closing:
537
543
  self._sleep_over_weekend(sessionmsg)
538
544
 
@@ -541,7 +547,7 @@ class Mt5ExecutionEngine:
541
547
  self._sleep_over_night(sessionmsg)
542
548
  elif today == FRIDAY and self._is_month_ends() and closing:
543
549
  self.strategy.perform_period_end_checks()
544
- exit(0)
550
+ sys.exit(0)
545
551
  else:
546
552
  self._sleep_over_weekend(sessionmsg)
547
553
 
@@ -621,17 +627,30 @@ class Mt5ExecutionEngine:
621
627
  )
622
628
  pass
623
629
 
624
- def _open_buy(
625
- self, signal, symbol, id, trade: Trade, price, stoplimit, sigmsg, msg, comment
626
- ):
630
+ def _handle_auto_trade(self, sigmsg, symbol) -> bool:
627
631
  if self.notify:
628
632
  self._send_notification(sigmsg, symbol)
633
+ if self.auto_trade:
634
+ return True
629
635
  if not self.auto_trade:
630
- auto_trade = input(
631
- f"{sigmsg} \n\n Please enter Y/Yes to accept this order or N/No to reject it :"
632
- )
636
+ prompt = f"{sigmsg} \n Enter Y/Yes to accept or N/No to reject this order : "
637
+ if self.prompt_callback is not None:
638
+ auto_trade = self.prompt_callback(prompt)
639
+ else:
640
+ auto_trade = input(prompt)
633
641
  if not auto_trade.upper().startswith("Y"):
634
- return
642
+ info = f"Order Rejected !!! SYMBOL={symbol}, STRATEGY={self.STRATEGY} , ACCOUNT={self.ACCOUNT}"
643
+ logger.info(info)
644
+ if self.notify:
645
+ self._send_notification(info, symbol)
646
+ return False
647
+ return True
648
+
649
+ def _open_buy(
650
+ self, signal, symbol, id, trade: Trade, price, stoplimit, sigmsg, msg, comment
651
+ ):
652
+ if not self._handle_auto_trade(sigmsg, symbol):
653
+ return
635
654
  if not self._check_retcode(trade, "BMKT"):
636
655
  logger.info(msg)
637
656
  trade.open_buy_position(
@@ -647,14 +666,8 @@ class Mt5ExecutionEngine:
647
666
  def _open_sell(
648
667
  self, signal, symbol, id, trade: Trade, price, stoplimit, sigmsg, msg, comment
649
668
  ):
650
- if self.notify:
651
- self._send_notification(sigmsg, symbol)
652
- if not self.auto_trade:
653
- auto_trade = input(
654
- f"{sigmsg} \n\n Please enter Y/Yes to accept this order or N/No to reject it :"
655
- )
656
- if not auto_trade.upper().startswith("Y"):
657
- return
669
+ if not self._handle_auto_trade(sigmsg, symbol):
670
+ return
658
671
  if not self._check_retcode(trade, "SMKT"):
659
672
  logger.info(msg)
660
673
  trade.open_sell_position(
@@ -905,7 +918,7 @@ class Mt5ExecutionEngine:
905
918
  pass
906
919
 
907
920
  def run(self):
908
- while True:
921
+ while self._running:
909
922
  try:
910
923
  check_mt5_connection(**self.kwargs)
911
924
  positions_orders = self._check_positions_orders()
@@ -927,13 +940,21 @@ class Mt5ExecutionEngine:
927
940
  self._sleep()
928
941
  self._handle_period_end_actions(today)
929
942
  except KeyboardInterrupt:
930
- logger.info("Stopping the Execution Engine ...")
943
+ logger.info(
944
+ f"Stopping Execution Engine for {self.STRATEGY} on {self.ACCOUNT}"
945
+ )
931
946
  break
932
947
  except Exception as e:
933
948
  msg = f"Running Execution Engine, STRATEGY={self.STRATEGY} , ACCOUNT={self.ACCOUNT}"
934
949
  self._print_exc(msg, e)
935
950
  continue
936
951
 
952
+ def stop(self):
953
+ """Stops the execution engine."""
954
+ self._running = False
955
+ logger.info(f"Stopping Execution Engine for {self.STRATEGY} on {self.ACCOUNT}")
956
+ logger.info("Execution Engine stopped successfully.")
957
+
937
958
 
938
959
  def RunMt5Engine(account_id: str, **kwargs):
939
960
  """Starts an MT5 execution engine for a given account.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bbstrader
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Simplified Investment & Trading Toolkit
5
5
  Home-page: https://github.com/bbalouki/bbstrader
6
6
  Download-URL: https://pypi.org/project/bbstrader/
@@ -172,10 +172,7 @@ To begin using `bbstrader`, please ensure your system meets the following prereq
172
172
  * [Admirals Group AS](https://cabinet.a-partnership.com/visit/?bta=35537&brand=admiralmarkets) (for Stocks, ETFs, Indices, Commodities, Futures, Forex)
173
173
  * [Just Global Markets Ltd.](https://one.justmarkets.link/a/tufvj0xugm/registration/trader) (for Stocks, Crypto, Indices, Commodities, Forex)
174
174
  * [FTMO](https://trader.ftmo.com/?affiliates=JGmeuQqepAZLMcdOEQRp) (Proprietary Firm)
175
- * **Interactive Brokers (IBKR)** (Optional, for IBKR integration):
176
- * Interactive Brokers Trader Workstation (TWS) or IB Gateway must be installed and running.
177
- * An active account with Interactive Brokers.
178
- * The Python client library for the IBKR API: `ibapi`.
175
+
179
176
 
180
177
  ### Installation
181
178
 
@@ -1,5 +1,5 @@
1
- bbstrader/__init__.py,sha256=5q_NaxJHcGYUVhC8cMWO3ZDJhjta7MrphQTYqganepY,581
2
- bbstrader/__main__.py,sha256=CMQB8_BPaXQ0ovQMHdEKri6kLPOVCBXw1nR2qJkA09I,2020
1
+ bbstrader/__init__.py,sha256=Uh0J99UbUAi55zL3HVBiYCmP1QP3F2Jw_8XQQJ5NNF0,581
2
+ bbstrader/__main__.py,sha256=zG8MuvuCSsFsnwqJDG9PU4t7EpYTqcx3cGNslLyRk5E,2168
3
3
  bbstrader/compat.py,sha256=djbHMvTvy0HYm1zyZ6Ttp_LMwP2PqTSVw1r7pqbz7So,487
4
4
  bbstrader/config.py,sha256=c2nCUw-bYWf5kkyFls5Nqld8HdMczexSilTni7rYUBw,3973
5
5
  bbstrader/tseries.py,sha256=IMoo_8Ov5m1Q2NJ3_RW8lzok8I8vUP5Ks7YGXwEZYsw,68385
@@ -13,35 +13,35 @@ bbstrader/btengine/portfolio.py,sha256=z98M65HQeCyma8gMZkAxspxBA9jtIhzxMyJUHPPj3
13
13
  bbstrader/btengine/scripts.py,sha256=8o66dq4Ex4DsH4s8xvJqUOFjLzZJSnbBvvNBzohtzoE,4837
14
14
  bbstrader/btengine/strategy.py,sha256=kLw4ipCTE06y2IdEysqI5VGlJDPEIR_OrJ3Qitm_yPw,32398
15
15
  bbstrader/core/__init__.py,sha256=GIFzFSStPfE0XM2j7mDeZZQeMTh_AwPsDOQXwMVJLgw,97
16
- bbstrader/core/data.py,sha256=n04Ph4TMC0o20iZkUw9VwdXPgqNUYeLh1Klkj6lMfEU,22590
16
+ bbstrader/core/data.py,sha256=u8hhAF1Gf9fr_2Ci4mv7Smr1dt3E_KDAHXC3BFbis0Q,25055
17
17
  bbstrader/core/scripts.py,sha256=orPtnQlNNNFV-yfqFGRAIGFtWgilykZ3xyTx6d4DLsk,3963
18
18
  bbstrader/core/utils.py,sha256=WjuabzBjhY65ku2KL-f7CMalE2x-wrX-6mCA_qhhFPE,2728
19
19
  bbstrader/ibkr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  bbstrader/ibkr/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  bbstrader/metatrader/__init__.py,sha256=A5Ye9tpc2sp9Xk5qjKw-EfYsoRcZtAt8nqvC3tCtZs8,333
22
- bbstrader/metatrader/account.py,sha256=rT53xK7IDUDhQj_G9rZFlTi3EgrQVEFppNSa3qmLp-g,56997
22
+ bbstrader/metatrader/account.py,sha256=5vi-InhcAHEDeuVz9WIY6Y-7LnWfKrhGMtbvRPsm1j8,56891
23
23
  bbstrader/metatrader/analysis.py,sha256=pnZWdvEnf9wkPT0vhEIbZipnN5EUf6TaQftplYP9jRs,3564
24
- bbstrader/metatrader/copier.py,sha256=YLu5tbw-IaG8Gs1bt64WdbracPOuZUXDGHdF6gaMTZM,32326
24
+ bbstrader/metatrader/copier.py,sha256=Vp8NbjUwUoQ_mOl9gGG1w43UsR_c8GiWtZA6V3Ph8xA,34948
25
25
  bbstrader/metatrader/rates.py,sha256=6B-5AHguyDhicw3GqJ33FfFpdCKzxgUdlrHyPFuOLZg,20784
26
26
  bbstrader/metatrader/risk.py,sha256=jOuMcK3Y7AeglHegPC-igB4ucMILB3BVm7o5sdits5I,27248
27
- bbstrader/metatrader/scripts.py,sha256=Yjp7Un-wDTInptHS_rPFpXNKWbVM871VEkaHxsO2MPQ,2115
28
- bbstrader/metatrader/trade.py,sha256=I4jm6TJEYdjPNczY9eLGtMKyWITXG0BbUNRbvdBIVgk,80531
29
- bbstrader/metatrader/utils.py,sha256=o1kn1z1LH07jx764MmUnTDRMNxCVeU7RzRMAtFcNLfo,19627
27
+ bbstrader/metatrader/scripts.py,sha256=z0dBNo3PTtDobk3U7iFYyALiwAictdNQ9eNSXOA0QQ0,2574
28
+ bbstrader/metatrader/trade.py,sha256=Ta1yc9g-GNKu1PI-qbFckbWWWm6NOYGnj6pyqyATktc,80419
29
+ bbstrader/metatrader/utils.py,sha256=aFP1XHxLkRfJFp7jKgY2BUlKKwZvCKnvC5qtY_vjgHg,19645
30
30
  bbstrader/models/__init__.py,sha256=s2mJrtKePXQaw_PvcrtPCD2mPCdVXP4Myzg0MlLVipo,547
31
31
  bbstrader/models/factors.py,sha256=Y1rjwhWU4aiSRd-jFOLnLZczFCY0bJUxauCo17HvOFY,12791
32
32
  bbstrader/models/ml.py,sha256=t8SOm5Wavv5CKXLJ7YtE99OwwQuJAlarlngdXQEjFjs,47602
33
- bbstrader/models/nlp.py,sha256=V_FdkVjELOKGT3k37d9rjK4Zve-TcizirIWwpeoX91Q,28749
33
+ bbstrader/models/nlp.py,sha256=0WuUREjk1N3IXwdzUKBK-aTvfD_TxmZ8gCNPrPYl4a4,31446
34
34
  bbstrader/models/optimization.py,sha256=vnks6uxFZdqXgxaZJNxq8z0IH45KZ8yaXo38JhIVKGc,6399
35
35
  bbstrader/models/portfolio.py,sha256=r-47Zrn2r7iKCHm5YVtwkbBJXAZGM3QYy-rXCWY9-Bg,8079
36
36
  bbstrader/models/risk.py,sha256=JQOXPshMOru6Eb0AMU6oKCNzg6mlGfL6_tN90lWcVBE,14878
37
37
  bbstrader/trading/__init__.py,sha256=ycLyuuxN5SujqtzR9X0Q74UQfK93q2va-GGAXdr-KS8,457
38
- bbstrader/trading/execution.py,sha256=nwLSfjdo-Pv_XgVM8wqIa60WmFtdSM3ho7OLmoqyPqg,37951
38
+ bbstrader/trading/execution.py,sha256=h8XoO1Ihi7sioy25L5545JFtdht3hqBQ-86StGsyYMs,38963
39
39
  bbstrader/trading/scripts.py,sha256=Tf5q33WqqygjpIv43_8nA82VZ3GM0qgb4Ggo3fHJ_wg,5744
40
40
  bbstrader/trading/strategies.py,sha256=BZEN8NwO9VxXDqSGc3o2OYaFyD9g5JKtEz_CyvxOOQM,37110
41
41
  bbstrader/trading/utils.py,sha256=57dKF9dcRu04oU2VRqydRrzW39dCW2wlDWhVt-sZdRw,1857
42
- bbstrader-0.3.0.dist-info/licenses/LICENSE,sha256=ZwC_RqqGmOPBUiMDKqLyJZ5HBeHq53LpL7TMRzrJY8c,1094
43
- bbstrader-0.3.0.dist-info/METADATA,sha256=KXxh1p3JNoBCX-xouPt3INb7VdOMVgoivzUtABSpyPw,27263
44
- bbstrader-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
45
- bbstrader-0.3.0.dist-info/entry_points.txt,sha256=0yDCbhbgHswOzJnY5wRSM_FjjyMHGvY7lJpSSVh0xtI,54
46
- bbstrader-0.3.0.dist-info/top_level.txt,sha256=Wwj322jZmxGZ6gD_TdaPiPLjED5ReObm5omerwlmZIg,10
47
- bbstrader-0.3.0.dist-info/RECORD,,
42
+ bbstrader-0.3.1.dist-info/licenses/LICENSE,sha256=ZwC_RqqGmOPBUiMDKqLyJZ5HBeHq53LpL7TMRzrJY8c,1094
43
+ bbstrader-0.3.1.dist-info/METADATA,sha256=Xi3741OMjW9hZmeep3Kvv1ucWWHC1wHr0IdCHczEv-4,26984
44
+ bbstrader-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
45
+ bbstrader-0.3.1.dist-info/entry_points.txt,sha256=0yDCbhbgHswOzJnY5wRSM_FjjyMHGvY7lJpSSVh0xtI,54
46
+ bbstrader-0.3.1.dist-info/top_level.txt,sha256=Wwj322jZmxGZ6gD_TdaPiPLjED5ReObm5omerwlmZIg,10
47
+ bbstrader-0.3.1.dist-info/RECORD,,