bbstrader 0.2.4__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.

@@ -0,0 +1,641 @@
1
+ from datetime import datetime
2
+ from enum import Enum
3
+ from typing import NamedTuple, Optional
4
+
5
+ import MetaTrader5 as MT5
6
+
7
+ __all__ = [
8
+ "TIMEFRAMES",
9
+ "TimeFrame",
10
+ "TerminalInfo",
11
+ "AccountInfo",
12
+ "SymbolInfo",
13
+ "TickInfo",
14
+ "TradeRequest",
15
+ "OrderCheckResult",
16
+ "OrderSentResult",
17
+ "TradeOrder",
18
+ "TradePosition",
19
+ "TradeDeal",
20
+ "InvalidBroker",
21
+ "GenericFail",
22
+ "InvalidParams",
23
+ "HistoryNotFound",
24
+ "InvalidVersion",
25
+ "AuthFailed",
26
+ "UnsupportedMethod",
27
+ "AutoTradingDisabled",
28
+ "InternalFailSend",
29
+ "InternalFailReceive",
30
+ "InternalFailInit",
31
+ "InternalFailConnect",
32
+ "InternalFailTimeout",
33
+ "trade_retcode_message",
34
+ "raise_mt5_error",
35
+ ]
36
+
37
+ # TIMEFRAME is an enumeration with possible chart period values
38
+ # See https://www.mql5.com/en/docs/python_metatrader5/mt5copyratesfrom_py#timeframe
39
+ TIMEFRAMES = {
40
+ "1m": MT5.TIMEFRAME_M1,
41
+ "2m": MT5.TIMEFRAME_M2,
42
+ "3m": MT5.TIMEFRAME_M3,
43
+ "4m": MT5.TIMEFRAME_M4,
44
+ "5m": MT5.TIMEFRAME_M5,
45
+ "6m": MT5.TIMEFRAME_M6,
46
+ "10m": MT5.TIMEFRAME_M10,
47
+ "12m": MT5.TIMEFRAME_M12,
48
+ "15m": MT5.TIMEFRAME_M15,
49
+ "20m": MT5.TIMEFRAME_M20,
50
+ "30m": MT5.TIMEFRAME_M30,
51
+ "1h": MT5.TIMEFRAME_H1,
52
+ "2h": MT5.TIMEFRAME_H2,
53
+ "3h": MT5.TIMEFRAME_H3,
54
+ "4h": MT5.TIMEFRAME_H4,
55
+ "6h": MT5.TIMEFRAME_H6,
56
+ "8h": MT5.TIMEFRAME_H8,
57
+ "12h": MT5.TIMEFRAME_H12,
58
+ "D1": MT5.TIMEFRAME_D1,
59
+ "W1": MT5.TIMEFRAME_W1,
60
+ "MN1": MT5.TIMEFRAME_MN1,
61
+ }
62
+
63
+
64
+ class TimeFrame(Enum):
65
+ """
66
+ Rrepresent a time frame object
67
+ """
68
+
69
+ M1 = "1m"
70
+ M2 = "2m"
71
+ M3 = "3m"
72
+ M4 = "4m"
73
+ M5 = "5m"
74
+ M6 = "6m"
75
+ M10 = "10m"
76
+ M12 = "12m"
77
+ M15 = "15m"
78
+ M20 = "20m"
79
+ M30 = "30m"
80
+ H1 = "1h"
81
+ H2 = "2h"
82
+ H3 = "3h"
83
+ H4 = "4h"
84
+ H6 = "6h"
85
+ H8 = "8h"
86
+ H12 = "12h"
87
+ D1 = "D1"
88
+ W1 = "W1"
89
+ MN1 = "MN1"
90
+
91
+
92
+ class TerminalInfo(NamedTuple):
93
+ """
94
+ Represents general information about the trading terminal.
95
+ See https://www.mql5.com/en/docs/constants/environment_state/terminalstatus
96
+ """
97
+
98
+ community_account: bool
99
+ community_connection: bool
100
+ connected: bool
101
+ dlls_allowed: bool
102
+ trade_allowed: bool
103
+ tradeapi_disabled: bool
104
+ email_enabled: bool
105
+ ftp_enabled: bool
106
+ notifications_enabled: bool
107
+ mqid: bool
108
+ build: int
109
+ maxbars: int
110
+ codepage: int
111
+ ping_last: int
112
+ community_balance: float
113
+ retransmission: float
114
+ company: str
115
+ name: str
116
+ language: str
117
+ path: str
118
+ data_path: str
119
+ commondata_path: str
120
+
121
+
122
+ class AccountInfo(NamedTuple):
123
+ """
124
+ Represents information about a trading account.
125
+ See https://www.mql5.com/en/docs/constants/environment_state/accountinformation
126
+ """
127
+
128
+ login: int
129
+ trade_mode: int
130
+ leverage: int
131
+ limit_orders: int
132
+ margin_so_mode: int
133
+ trade_allowed: bool
134
+ trade_expert: bool
135
+ margin_mode: int
136
+ currency_digits: int
137
+ fifo_close: bool
138
+ balance: float
139
+ credit: float
140
+ profit: float
141
+ equity: float
142
+ margin: float
143
+ margin_free: float
144
+ margin_level: float
145
+ margin_so_call: float
146
+ margin_so_so: float
147
+ margin_initial: float
148
+ margin_maintenance: float
149
+ assets: float
150
+ liabilities: float
151
+ commission_blocked: float
152
+ name: str
153
+ server: str
154
+ currency: str
155
+ company: str
156
+
157
+
158
+ class SymbolInfo(NamedTuple):
159
+ """
160
+ Represents detailed information about a financial instrument.
161
+ See https://www.mql5.com/en/docs/constants/environment_state/marketinfoconstants
162
+ """
163
+
164
+ custom: bool
165
+ chart_mode: int
166
+ select: bool
167
+ visible: bool
168
+ session_deals: int
169
+ session_buy_orders: int
170
+ session_sell_orders: int
171
+ volume: int
172
+ volumehigh: int
173
+ volumelow: int
174
+ time: datetime
175
+ digits: int
176
+ spread: int
177
+ spread_float: bool
178
+ ticks_bookdepth: int
179
+ trade_calc_mode: int
180
+ trade_mode: int
181
+ start_time: int
182
+ expiration_time: int
183
+ trade_stops_level: int
184
+ trade_freeze_level: int
185
+ trade_exemode: int
186
+ swap_mode: int
187
+ swap_rollover3days: int
188
+ margin_hedged_use_leg: bool
189
+ expiration_mode: int
190
+ filling_mode: int
191
+ order_mode: int
192
+ order_gtc_mode: int
193
+ option_mode: int
194
+ option_right: int
195
+ bid: float
196
+ bidhigh: float
197
+ bidlow: float
198
+ ask: float
199
+ askhigh: float
200
+ asklow: float
201
+ last: float
202
+ lasthigh: float
203
+ lastlow: float
204
+ volume_real: float
205
+ volumehigh_real: float
206
+ volumelow_real: float
207
+ option_strike: float
208
+ point: float
209
+ trade_tick_value: float
210
+ trade_tick_value_profit: float
211
+ trade_tick_value_loss: float
212
+ trade_tick_size: float
213
+ trade_contract_size: float
214
+ trade_accrued_interest: float
215
+ trade_face_value: float
216
+ trade_liquidity_rate: float
217
+ volume_min: float
218
+ volume_max: float
219
+ volume_step: float
220
+ volume_limit: float
221
+ swap_long: float
222
+ swap_short: float
223
+ margin_initial: float
224
+ margin_maintenance: float
225
+ session_volume: float
226
+ session_turnover: float
227
+ session_interest: float
228
+ session_buy_orders_volume: float
229
+ session_sell_orders_volume: float
230
+ session_open: float
231
+ session_close: float
232
+ session_aw: float
233
+ session_price_settlement: float
234
+ session_price_limit_min: float
235
+ session_price_limit_max: float
236
+ margin_hedged: float
237
+ price_change: float
238
+ price_volatility: float
239
+ price_theoretical: float
240
+ price_greeks_delta: float
241
+ price_greeks_theta: float
242
+ price_greeks_gamma: float
243
+ price_greeks_vega: float
244
+ price_greeks_rho: float
245
+ price_greeks_omega: float
246
+ price_sensitivity: float
247
+ basis: str
248
+ category: str
249
+ currency_base: str
250
+ currency_profit: str
251
+ currency_margin: str
252
+ bank: str
253
+ description: str
254
+ exchange: str
255
+ formula: str
256
+ isin: str
257
+ name: str
258
+ page: str
259
+ path: str
260
+
261
+
262
+ class TickInfo(NamedTuple):
263
+ """
264
+ Represents the last tick for the specified financial instrument.
265
+ * time: Time of the last prices update
266
+ * bid: Current Bid price
267
+ * ask: Current Ask price
268
+ * last: Price of the last deal (Last)
269
+ * volume: Volume for the current Last price
270
+ * time_msc: Time of a price last update in milliseconds
271
+ * flags: Tick flags
272
+ * volume_real: Volume for the current Last price with greater accuracy
273
+ """
274
+
275
+ time: datetime
276
+ bid: float
277
+ ask: float
278
+ last: float
279
+ volume: int
280
+ time_msc: int
281
+ flags: int
282
+ volume_real: float
283
+
284
+
285
+ class TradeRequest(NamedTuple):
286
+ """
287
+ Represents a Trade Request Structure
288
+ See https://www.mql5.com/en/docs/constants/structures/mqltraderequest
289
+ """
290
+
291
+ action: int
292
+ magic: int
293
+ order: int
294
+ symbol: str
295
+ volume: float
296
+ price: float
297
+ stoplimit: float
298
+ sl: float
299
+ tp: float
300
+ deviation: int
301
+ type: int
302
+ type_filling: int
303
+ type_time: int
304
+ expiration: int
305
+ comment: str
306
+ position: int
307
+ position_by: int
308
+
309
+
310
+ class OrderCheckResult(NamedTuple):
311
+ """
312
+ The Structure of Results of a Trade Request Check
313
+ See https://www.mql5.com/en/docs/constants/structures/mqltradecheckresult
314
+ """
315
+
316
+ retcode: int
317
+ balance: float
318
+ equity: float
319
+ profit: float
320
+ margin: float
321
+ margin_free: float
322
+ margin_level: float
323
+ comment: str
324
+ request: TradeRequest
325
+
326
+
327
+ class OrderSentResult(NamedTuple):
328
+ """
329
+ The Structure of a Trade Request Result
330
+ See https://www.mql5.com/en/docs/constants/structures/mqltraderesult
331
+ """
332
+
333
+ retcode: int
334
+ deal: int
335
+ order: int
336
+ volume: float
337
+ price: float
338
+ bid: float
339
+ ask: float
340
+ comment: str
341
+ request_id: int
342
+ retcode_external: int
343
+ request: TradeRequest
344
+
345
+
346
+ class TradeOrder(NamedTuple):
347
+ """
348
+ Represents a trade order.
349
+ See https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties
350
+ """
351
+
352
+ ticket: int
353
+ time_setup: int
354
+ time_setup_msc: int
355
+ time_done: int
356
+ time_done_msc: int
357
+ time_expiration: int
358
+ type: int
359
+ type_time: int
360
+ type_filling: int
361
+ state: int
362
+ magic: int
363
+ position_id: int
364
+ position_by_id: int
365
+ reason: int
366
+ volume_initial: float
367
+ volume_current: float
368
+ price_open: float
369
+ sl: float # Stop Loss
370
+ tp: float # Take Profit
371
+ price_current: float
372
+ price_stoplimit: float
373
+ symbol: str
374
+ comment: str
375
+ external_id: str
376
+
377
+
378
+ class TradePosition(NamedTuple):
379
+ """
380
+ Represents a trade position with attributes like ticket, open/close prices,
381
+ volume, profit, and other trading details.
382
+ See https://www.mql5.com/en/docs/constants/tradingconstants/positionproperties
383
+ """
384
+
385
+ ticket: int
386
+ time: int
387
+ time_msc: int
388
+ time_update: int
389
+ time_update_msc: int
390
+ type: int
391
+ magic: int
392
+ identifier: int
393
+ reason: int
394
+ volume: float
395
+ price_open: float
396
+ sl: float # Stop Loss
397
+ tp: float # Take Profit
398
+ price_current: float
399
+ swap: float
400
+ profit: float
401
+ symbol: str
402
+ comment: str
403
+ external_id: str
404
+
405
+
406
+ class TradeDeal(NamedTuple):
407
+ """
408
+ Represents a trade deal execution.
409
+ See https://www.mql5.com/en/docs/constants/tradingconstants/dealproperties
410
+ """
411
+
412
+ ticket: int
413
+ order: int
414
+ time: int
415
+ time_msc: int
416
+ type: int
417
+ entry: int
418
+ magic: int
419
+ position_id: int
420
+ reason: int
421
+ volume: float
422
+ price: float
423
+ commission: float
424
+ swap: float
425
+ profit: float
426
+ fee: float
427
+ symbol: str
428
+ comment: str
429
+ external_id: str
430
+
431
+
432
+ class InvalidBroker(Exception):
433
+ """Exception raised for invalid broker errors."""
434
+
435
+ def __init__(self, message="Invalid broker."):
436
+ super().__init__(message)
437
+
438
+
439
+ class MT5TerminalError(Exception):
440
+ """Base exception class for trading-related errors."""
441
+
442
+ def __init__(self, code, message):
443
+ super().__init__(message)
444
+ self.code = code
445
+ self.message = message
446
+
447
+ def __str__(self) -> str:
448
+ if self.message is None:
449
+ return f"{self.__class__.__name__}"
450
+ else:
451
+ return f"{self.__class__.__name__}, {self.message}"
452
+
453
+
454
+ class GenericFail(MT5TerminalError):
455
+ """Exception raised for generic failure."""
456
+
457
+ def __init__(self, message="Generic fail"):
458
+ super().__init__(MT5.RES_E_FAIL, message)
459
+
460
+
461
+ class InvalidParams(MT5TerminalError):
462
+ """Exception raised for invalid arguments or parameters."""
463
+
464
+ def __init__(self, message="Invalid arguments or parameters."):
465
+ super().__init__(MT5.RES_E_INVALID_PARAMS, message)
466
+
467
+
468
+ class HistoryNotFound(MT5TerminalError):
469
+ """Exception raised when no history is found."""
470
+
471
+ def __init__(self, message="No history found."):
472
+ super().__init__(MT5.RES_E_NOT_FOUND, message)
473
+
474
+
475
+ class InvalidVersion(MT5TerminalError):
476
+ """Exception raised for an invalid version."""
477
+
478
+ def __init__(self, message="Invalid version."):
479
+ super().__init__(MT5.RES_E_INVALID_VERSION, message)
480
+
481
+
482
+ class AuthFailed(MT5TerminalError):
483
+ """Exception raised for authorization failure."""
484
+
485
+ def __init__(self, message="Authorization failed."):
486
+ super().__init__(MT5.RES_E_AUTH_FAILED, message)
487
+
488
+
489
+ class UnsupportedMethod(MT5TerminalError):
490
+ """Exception raised for an unsupported method."""
491
+
492
+ def __init__(self, message="Unsupported method."):
493
+ super().__init__(MT5.RES_E_UNSUPPORTED, message)
494
+
495
+
496
+ class AutoTradingDisabled(MT5TerminalError):
497
+ """Exception raised when auto-trading is disabled."""
498
+
499
+ def __init__(self, message="Auto-trading is disabled."):
500
+ super().__init__(MT5.RES_E_AUTO_TRADING_DISABLED, message)
501
+
502
+
503
+ class InternalFailError(MT5TerminalError):
504
+ """Base exception class for internal IPC errors."""
505
+
506
+ pass
507
+
508
+
509
+ class InternalFailSend(InternalFailError):
510
+ """Exception raised for internal IPC send failure."""
511
+
512
+ def __init__(self, message="Internal IPC send failed."):
513
+ super().__init__(MT5.RES_E_INTERNAL_FAIL_SEND, message)
514
+
515
+
516
+ class InternalFailReceive(InternalFailError):
517
+ """Exception raised for internal IPC receive failure."""
518
+
519
+ def __init__(self, message="Internal IPC receive failed."):
520
+ super().__init__(MT5.RES_E_INTERNAL_FAIL_RECEIVE, message)
521
+
522
+
523
+ class InternalFailInit(InternalFailError):
524
+ """Exception raised for internal IPC initialization failure."""
525
+
526
+ def __init__(self, message="Internal IPC initialization failed."):
527
+ super().__init__(MT5.RES_E_INTERNAL_FAIL_INIT, message)
528
+
529
+
530
+ class InternalFailConnect(InternalFailError):
531
+ """Exception raised for no IPC connection."""
532
+
533
+ def __init__(self, message="No IPC connection."):
534
+ super().__init__(MT5.RES_E_INTERNAL_FAIL_CONNECT, message)
535
+
536
+
537
+ class InternalFailTimeout(InternalFailError):
538
+ """Exception raised for an internal timeout."""
539
+
540
+ def __init__(self, message="Internal timeout."):
541
+ super().__init__(MT5.RES_E_INTERNAL_FAIL_TIMEOUT, message)
542
+
543
+
544
+ # Dictionary to map error codes to exception classes
545
+ _ERROR_CODE_TO_EXCEPTION_ = {
546
+ MT5.RES_E_FAIL: GenericFail,
547
+ MT5.RES_E_INVALID_PARAMS: InvalidParams,
548
+ MT5.RES_E_NOT_FOUND: HistoryNotFound,
549
+ MT5.RES_E_INVALID_VERSION: InvalidVersion,
550
+ MT5.RES_E_AUTH_FAILED: AuthFailed,
551
+ MT5.RES_E_UNSUPPORTED: UnsupportedMethod,
552
+ MT5.RES_E_AUTO_TRADING_DISABLED: AutoTradingDisabled,
553
+ MT5.RES_E_INTERNAL_FAIL_SEND: InternalFailSend,
554
+ MT5.RES_E_INTERNAL_FAIL_RECEIVE: InternalFailReceive,
555
+ MT5.RES_E_INTERNAL_FAIL_INIT: InternalFailInit,
556
+ MT5.RES_E_INTERNAL_FAIL_CONNECT: InternalFailConnect,
557
+ MT5.RES_E_INTERNAL_FAIL_TIMEOUT: InternalFailTimeout,
558
+ }
559
+
560
+
561
+ def raise_mt5_error(message: Optional[str] = None):
562
+ """Raises an exception based on the given error code.
563
+
564
+ Args:
565
+ message: An optional custom error message.
566
+
567
+ Raises:
568
+ MT5TerminalError: A specific exception based on the error code.
569
+ """
570
+ error = _ERROR_CODE_TO_EXCEPTION_.get(MT5.last_error()[0])
571
+ raise Exception(f"{error(None)} {message or MT5.last_error()[1]}")
572
+
573
+
574
+ _ORDER_FILLING_TYPE_ = "https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties#enum_order_type_filling"
575
+ _ORDER_TYPE_ = "https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties#enum_order_type"
576
+ _POSITION_IDENTIFIER_ = "https://www.mql5.com/en/docs/constants/tradingconstants/positionproperties#enum_position_property_integer"
577
+ _FIFO_RULE_ = "https://www.mql5.com/en/docs/constants/environment_state/accountinformation#enum_account_info_integer"
578
+
579
+ _TRADE_RETCODE_MESSAGES_ = {
580
+ 10004: "Requote: The price has changed, please try again",
581
+ 10006: "Request rejected",
582
+ 10007: "Request canceled by trader",
583
+ 10008: "Order placed",
584
+ 10009: "Request completed",
585
+ 10010: "Only part of the request was completed",
586
+ 10011: "Request processing error",
587
+ 10012: "Request canceled by timeout",
588
+ 10013: "Invalid request",
589
+ 10014: "Invalid volume in the request",
590
+ 10015: "Invalid price in the request",
591
+ 10016: "Invalid stops in the request",
592
+ 10017: "Trade is disabled",
593
+ 10018: "Market is closed",
594
+ 10019: "Insufficient funds to complete the request",
595
+ 10020: "Prices changed",
596
+ 10021: "No quotes to process the request",
597
+ 10022: "Invalid order expiration date in the request",
598
+ 10023: "Order state changed",
599
+ 10024: "Too many requests, please try again later",
600
+ 10025: "No changes in request",
601
+ 10026: "Autotrading disabled by server",
602
+ 10027: "Autotrading disabled by client terminal",
603
+ 10028: "Request locked for processing",
604
+ 10029: "Order or position frozen",
605
+ 10030: "Invalid order filling type: see" + " " + _ORDER_FILLING_TYPE_,
606
+ 10031: "No connection with the trade server",
607
+ 10032: "Operation allowed only for live accounts",
608
+ 10033: "The number of pending orders has reached the limit",
609
+ 10034: "Order/position volume limit for the symbol reached",
610
+ 10035: "Incorrect or prohibited order type: see" + " " + _ORDER_TYPE_,
611
+ 10036: "Position with the specified ID has already been closed: see"
612
+ + " "
613
+ + _POSITION_IDENTIFIER_,
614
+ 10038: "Close volume exceeds the current position volume",
615
+ 10039: "A close order already exists for this position",
616
+ 10040: "Maximum number of open positions reached",
617
+ 10041: "Pending order activation rejected, order canceled",
618
+ 10042: "Only long positions are allowed",
619
+ 10043: "Only short positions are allowed",
620
+ 10044: "Only position closing is allowed",
621
+ 10045: "Position closing allowed only by FIFO rule: see" + " " + _FIFO_RULE_,
622
+ 10046: "Opposite positions on this symbol are disabled",
623
+ }
624
+
625
+
626
+ def trade_retcode_message(code, display=False, add_msg=""):
627
+ """
628
+ Retrieves a user-friendly message corresponding to a given trade return code.
629
+
630
+ Args:
631
+ code (int): The trade return code to look up.
632
+ display (bool, optional): Whether to print the message to the console. Defaults to False.
633
+
634
+ Returns:
635
+ str: The message associated with the provided trade return code. If the code is not found,
636
+ it returns "Unknown trade error.".
637
+ """
638
+ message = _TRADE_RETCODE_MESSAGES_.get(code, "Unknown trade error")
639
+ if display:
640
+ print(message + add_msg)
641
+ return message
@@ -0,0 +1,10 @@
1
+ """
2
+ The `models` module provides a foundational framework for implementing various quantitative finance models.
3
+
4
+ It is designed to be a versatile base module for different types of models used in financial analysis and trading.
5
+ """
6
+ from bbstrader.models.risk import * # noqa: F403
7
+ from bbstrader.models.optimization import * # noqa: F403
8
+ from bbstrader.models.portfolio import * # noqa: F403
9
+ from bbstrader.models.factors import * # noqa: F403
10
+ from bbstrader.models.ml import * # noqa: F403