bbstrader 2.0.3__cp312-cp312-macosx_11_0_arm64.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.
- bbstrader/__init__.py +27 -0
- bbstrader/__main__.py +92 -0
- bbstrader/api/__init__.py +96 -0
- bbstrader/api/handlers.py +245 -0
- bbstrader/api/metatrader_client.cpython-312-darwin.so +0 -0
- bbstrader/api/metatrader_client.pyi +624 -0
- bbstrader/assets/bbs_.png +0 -0
- bbstrader/assets/bbstrader.ico +0 -0
- bbstrader/assets/bbstrader.png +0 -0
- bbstrader/assets/qs_metrics_1.png +0 -0
- bbstrader/btengine/__init__.py +54 -0
- bbstrader/btengine/backtest.py +358 -0
- bbstrader/btengine/data.py +737 -0
- bbstrader/btengine/event.py +229 -0
- bbstrader/btengine/execution.py +287 -0
- bbstrader/btengine/performance.py +408 -0
- bbstrader/btengine/portfolio.py +393 -0
- bbstrader/btengine/strategy.py +588 -0
- bbstrader/compat.py +28 -0
- bbstrader/config.py +100 -0
- bbstrader/core/__init__.py +27 -0
- bbstrader/core/data.py +628 -0
- bbstrader/core/strategy.py +466 -0
- bbstrader/metatrader/__init__.py +48 -0
- bbstrader/metatrader/_copier.py +720 -0
- bbstrader/metatrader/account.py +865 -0
- bbstrader/metatrader/broker.py +418 -0
- bbstrader/metatrader/copier.py +1487 -0
- bbstrader/metatrader/rates.py +495 -0
- bbstrader/metatrader/risk.py +667 -0
- bbstrader/metatrader/trade.py +1692 -0
- bbstrader/metatrader/utils.py +402 -0
- bbstrader/models/__init__.py +39 -0
- bbstrader/models/nlp.py +932 -0
- bbstrader/models/optimization.py +182 -0
- bbstrader/scripts.py +665 -0
- bbstrader/trading/__init__.py +33 -0
- bbstrader/trading/execution.py +1159 -0
- bbstrader/trading/strategy.py +362 -0
- bbstrader/trading/utils.py +69 -0
- bbstrader-2.0.3.dist-info/METADATA +396 -0
- bbstrader-2.0.3.dist-info/RECORD +45 -0
- bbstrader-2.0.3.dist-info/WHEEL +5 -0
- bbstrader-2.0.3.dist-info/entry_points.txt +3 -0
- bbstrader-2.0.3.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import NamedTuple, Optional
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
import MetaTrader5 as MT5
|
|
8
|
+
except ImportError:
|
|
9
|
+
import bbstrader.compat # noqa: F401
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"TIMEFRAMES",
|
|
14
|
+
"RateInfo",
|
|
15
|
+
"RateDtype",
|
|
16
|
+
"TimeFrame",
|
|
17
|
+
"SymbolType",
|
|
18
|
+
"InvalidBroker",
|
|
19
|
+
"GenericFail",
|
|
20
|
+
"InvalidParams",
|
|
21
|
+
"HistoryNotFound",
|
|
22
|
+
"InvalidVersion",
|
|
23
|
+
"AuthFailed",
|
|
24
|
+
"UnsupportedMethod",
|
|
25
|
+
"AutoTradingDisabled",
|
|
26
|
+
"InternalFailSend",
|
|
27
|
+
"InternalFailReceive",
|
|
28
|
+
"InternalFailInit",
|
|
29
|
+
"InternalFailConnect",
|
|
30
|
+
"InternalFailTimeout",
|
|
31
|
+
"trade_retcode_message",
|
|
32
|
+
"raise_mt5_error",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
# TIMEFRAME is an enumeration with possible chart period values
|
|
36
|
+
# See https://www.mql5.com/en/docs/python_metatrader5/mt5copyratesfrom_py#timeframe
|
|
37
|
+
TIMEFRAMES = {
|
|
38
|
+
"1m": MT5.TIMEFRAME_M1,
|
|
39
|
+
"2m": MT5.TIMEFRAME_M2,
|
|
40
|
+
"3m": MT5.TIMEFRAME_M3,
|
|
41
|
+
"4m": MT5.TIMEFRAME_M4,
|
|
42
|
+
"5m": MT5.TIMEFRAME_M5,
|
|
43
|
+
"6m": MT5.TIMEFRAME_M6,
|
|
44
|
+
"10m": MT5.TIMEFRAME_M10,
|
|
45
|
+
"12m": MT5.TIMEFRAME_M12,
|
|
46
|
+
"15m": MT5.TIMEFRAME_M15,
|
|
47
|
+
"20m": MT5.TIMEFRAME_M20,
|
|
48
|
+
"30m": MT5.TIMEFRAME_M30,
|
|
49
|
+
"1h": MT5.TIMEFRAME_H1,
|
|
50
|
+
"2h": MT5.TIMEFRAME_H2,
|
|
51
|
+
"3h": MT5.TIMEFRAME_H3,
|
|
52
|
+
"4h": MT5.TIMEFRAME_H4,
|
|
53
|
+
"6h": MT5.TIMEFRAME_H6,
|
|
54
|
+
"8h": MT5.TIMEFRAME_H8,
|
|
55
|
+
"12h": MT5.TIMEFRAME_H12,
|
|
56
|
+
"D1": MT5.TIMEFRAME_D1,
|
|
57
|
+
"W1": MT5.TIMEFRAME_W1,
|
|
58
|
+
"MN1": MT5.TIMEFRAME_MN1,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class TimeFrame(Enum):
|
|
63
|
+
"""
|
|
64
|
+
Rrepresent a time frame object
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
M1 = TIMEFRAMES["1m"]
|
|
68
|
+
M2 = TIMEFRAMES["2m"]
|
|
69
|
+
M3 = TIMEFRAMES["3m"]
|
|
70
|
+
M4 = TIMEFRAMES["4m"]
|
|
71
|
+
M5 = TIMEFRAMES["5m"]
|
|
72
|
+
M6 = TIMEFRAMES["6m"]
|
|
73
|
+
M10 = TIMEFRAMES["10m"]
|
|
74
|
+
M12 = TIMEFRAMES["12m"]
|
|
75
|
+
M15 = TIMEFRAMES["15m"]
|
|
76
|
+
M20 = TIMEFRAMES["20m"]
|
|
77
|
+
M30 = TIMEFRAMES["30m"]
|
|
78
|
+
H1 = TIMEFRAMES["1h"]
|
|
79
|
+
H2 = TIMEFRAMES["2h"]
|
|
80
|
+
H3 = TIMEFRAMES["3h"]
|
|
81
|
+
H4 = TIMEFRAMES["4h"]
|
|
82
|
+
H6 = TIMEFRAMES["6h"]
|
|
83
|
+
H8 = TIMEFRAMES["8h"]
|
|
84
|
+
H12 = TIMEFRAMES["12h"]
|
|
85
|
+
D1 = TIMEFRAMES["D1"]
|
|
86
|
+
W1 = TIMEFRAMES["W1"]
|
|
87
|
+
MN1 = TIMEFRAMES["MN1"]
|
|
88
|
+
|
|
89
|
+
def __str__(self):
|
|
90
|
+
"""Return the string representation of the time frame."""
|
|
91
|
+
return self.name
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class SymbolType(Enum):
|
|
95
|
+
"""
|
|
96
|
+
Represents the type of a symbol.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
FOREX = "FOREX" # Forex currency pairs
|
|
100
|
+
FUTURES = "FUTURES" # Futures contracts
|
|
101
|
+
STOCKS = "STOCKS" # Stocks and shares
|
|
102
|
+
BONDS = "BONDS" # Bonds
|
|
103
|
+
CRYPTO = "CRYPTO" # Cryptocurrencies
|
|
104
|
+
ETFs = "ETFs" # Exchange-Traded Funds
|
|
105
|
+
INDICES = "INDICES" # Market indices
|
|
106
|
+
COMMODITIES = "COMMODITIES" # Commodities
|
|
107
|
+
OPTIONS = "OPTIONS" # Options contracts
|
|
108
|
+
unknown = "UNKNOWN" # Unknown or unsupported type
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
RateDtype = np.dtype(
|
|
112
|
+
[
|
|
113
|
+
("time", "<i8"),
|
|
114
|
+
("open", "<f8"),
|
|
115
|
+
("high", "<f8"),
|
|
116
|
+
("low", "<f8"),
|
|
117
|
+
("close", "<f8"),
|
|
118
|
+
("tick_volume", "<u8"),
|
|
119
|
+
("spread", "<i4"),
|
|
120
|
+
("real_volume", "<u8"),
|
|
121
|
+
]
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class RateInfo(NamedTuple):
|
|
126
|
+
"""
|
|
127
|
+
Reprents a candle (bar) for a specified period.
|
|
128
|
+
* time: Time in seconds since 1970.01.01 00:00
|
|
129
|
+
* open: Open price
|
|
130
|
+
* high: High price
|
|
131
|
+
* low: Low price
|
|
132
|
+
* close: Close price
|
|
133
|
+
* tick_volume: Tick volume
|
|
134
|
+
* spread: Spread value
|
|
135
|
+
* real_volume: Real volume
|
|
136
|
+
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
time: int
|
|
140
|
+
open: float
|
|
141
|
+
high: float
|
|
142
|
+
low: float
|
|
143
|
+
close: float
|
|
144
|
+
tick_volume: float
|
|
145
|
+
spread: int
|
|
146
|
+
real_volume: float
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class InvalidBroker(Exception):
|
|
150
|
+
"""Exception raised for invalid broker errors."""
|
|
151
|
+
|
|
152
|
+
def __init__(self, message="Invalid broker."):
|
|
153
|
+
super().__init__(message)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class MT5TerminalError(Exception):
|
|
157
|
+
"""Base exception class for trading-related errors."""
|
|
158
|
+
|
|
159
|
+
def __init__(self, code, message):
|
|
160
|
+
super().__init__(message)
|
|
161
|
+
self.code = code
|
|
162
|
+
self.message = message
|
|
163
|
+
|
|
164
|
+
def __repr__(self) -> str:
|
|
165
|
+
msg_str = str(self.message) if self.message is not None else ""
|
|
166
|
+
return f"{self.code} - {self.__class__.__name__}: {msg_str}"
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class GenericFail(MT5TerminalError):
|
|
170
|
+
"""Exception raised for generic failure."""
|
|
171
|
+
|
|
172
|
+
def __init__(self, message="Generic fail"):
|
|
173
|
+
super().__init__(MT5.RES_E_FAIL, message)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class InvalidParams(MT5TerminalError):
|
|
177
|
+
"""Exception raised for invalid arguments or parameters."""
|
|
178
|
+
|
|
179
|
+
def __init__(self, message="Invalid arguments or parameters."):
|
|
180
|
+
super().__init__(MT5.RES_E_INVALID_PARAMS, message)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class HistoryNotFound(MT5TerminalError):
|
|
184
|
+
"""Exception raised when no history is found."""
|
|
185
|
+
|
|
186
|
+
def __init__(self, message="No history found."):
|
|
187
|
+
super().__init__(MT5.RES_E_NOT_FOUND, message)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class InvalidVersion(MT5TerminalError):
|
|
191
|
+
"""Exception raised for an invalid version."""
|
|
192
|
+
|
|
193
|
+
def __init__(self, message="Invalid version."):
|
|
194
|
+
super().__init__(MT5.RES_E_INVALID_VERSION, message)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class AuthFailed(MT5TerminalError):
|
|
198
|
+
"""Exception raised for authorization failure."""
|
|
199
|
+
|
|
200
|
+
def __init__(self, message="Authorization failed."):
|
|
201
|
+
super().__init__(MT5.RES_E_AUTH_FAILED, message)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class UnsupportedMethod(MT5TerminalError):
|
|
205
|
+
"""Exception raised for an unsupported method."""
|
|
206
|
+
|
|
207
|
+
def __init__(self, message="Unsupported method."):
|
|
208
|
+
super().__init__(MT5.RES_E_UNSUPPORTED, message)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class AutoTradingDisabled(MT5TerminalError):
|
|
212
|
+
"""Exception raised when auto-trading is disabled."""
|
|
213
|
+
|
|
214
|
+
def __init__(self, message="Auto-trading is disabled."):
|
|
215
|
+
super().__init__(MT5.RES_E_AUTO_TRADING_DISABLED, message)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class InternalFailError(MT5TerminalError):
|
|
219
|
+
"""Base exception class for internal IPC errors."""
|
|
220
|
+
|
|
221
|
+
def __init__(self, code, message):
|
|
222
|
+
super().__init__(code, message)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class InternalFailSend(InternalFailError):
|
|
226
|
+
"""Exception raised for internal IPC send failure."""
|
|
227
|
+
|
|
228
|
+
def __init__(self, message="Internal IPC send failed."):
|
|
229
|
+
super().__init__(MT5.RES_E_INTERNAL_FAIL_SEND, message)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class InternalFailReceive(InternalFailError):
|
|
233
|
+
"""Exception raised for internal IPC receive failure."""
|
|
234
|
+
|
|
235
|
+
def __init__(self, message="Internal IPC receive failed."):
|
|
236
|
+
super().__init__(MT5.RES_E_INTERNAL_FAIL_RECEIVE, message)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class InternalFailInit(InternalFailError):
|
|
240
|
+
"""Exception raised for internal IPC initialization failure."""
|
|
241
|
+
|
|
242
|
+
def __init__(self, message="Internal IPC initialization failed."):
|
|
243
|
+
super().__init__(MT5.RES_E_INTERNAL_FAIL_INIT, message)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
class InternalFailConnect(InternalFailError):
|
|
247
|
+
"""Exception raised for no IPC connection."""
|
|
248
|
+
|
|
249
|
+
def __init__(self, message="No IPC connection."):
|
|
250
|
+
super().__init__(MT5.RES_E_INTERNAL_FAIL_CONNECT, message)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class InternalFailTimeout(InternalFailError):
|
|
254
|
+
"""Exception raised for an internal timeout."""
|
|
255
|
+
|
|
256
|
+
def __init__(self, message="Internal timeout."):
|
|
257
|
+
super().__init__(MT5.RES_E_INTERNAL_FAIL_TIMEOUT, message)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
RES_E_FAIL = 1 # Generic error
|
|
261
|
+
RES_E_INVALID_PARAMS = 2 # Invalid parameters
|
|
262
|
+
RES_E_NOT_FOUND = 3 # Not found
|
|
263
|
+
RES_E_INVALID_VERSION = 4 # Invalid version
|
|
264
|
+
RES_E_AUTH_FAILED = 5 # Authorization failed
|
|
265
|
+
RES_E_UNSUPPORTED = 6 # Unsupported method
|
|
266
|
+
RES_E_AUTO_TRADING_DISABLED = 7 # Autotrading disabled
|
|
267
|
+
|
|
268
|
+
# Actual internal error codes from MetaTrader5
|
|
269
|
+
RES_E_INTERNAL_FAIL_CONNECT = -10000
|
|
270
|
+
RES_E_INTERNAL_FAIL_INIT = -10001
|
|
271
|
+
RES_E_INTERNAL_FAIL_SEND = -10006
|
|
272
|
+
RES_E_INTERNAL_FAIL_RECEIVE = -10007
|
|
273
|
+
RES_E_INTERNAL_FAIL_TIMEOUT = -10008
|
|
274
|
+
|
|
275
|
+
# Dictionary to map error codes to exception classes
|
|
276
|
+
_ERROR_CODE_TO_EXCEPTION_ = {
|
|
277
|
+
MT5.RES_E_FAIL: GenericFail,
|
|
278
|
+
MT5.RES_E_INVALID_PARAMS: InvalidParams,
|
|
279
|
+
MT5.RES_E_NOT_FOUND: HistoryNotFound,
|
|
280
|
+
MT5.RES_E_INVALID_VERSION: InvalidVersion,
|
|
281
|
+
MT5.RES_E_AUTH_FAILED: AuthFailed,
|
|
282
|
+
MT5.RES_E_UNSUPPORTED: UnsupportedMethod,
|
|
283
|
+
MT5.RES_E_AUTO_TRADING_DISABLED: AutoTradingDisabled,
|
|
284
|
+
MT5.RES_E_INTERNAL_FAIL_SEND: InternalFailSend,
|
|
285
|
+
MT5.RES_E_INTERNAL_FAIL_RECEIVE: InternalFailReceive,
|
|
286
|
+
MT5.RES_E_INTERNAL_FAIL_INIT: InternalFailInit,
|
|
287
|
+
MT5.RES_E_INTERNAL_FAIL_CONNECT: InternalFailConnect,
|
|
288
|
+
MT5.RES_E_INTERNAL_FAIL_TIMEOUT: InternalFailTimeout,
|
|
289
|
+
RES_E_FAIL: GenericFail,
|
|
290
|
+
RES_E_INVALID_PARAMS: InvalidParams,
|
|
291
|
+
RES_E_NOT_FOUND: HistoryNotFound,
|
|
292
|
+
RES_E_INVALID_VERSION: InvalidVersion,
|
|
293
|
+
RES_E_AUTH_FAILED: AuthFailed,
|
|
294
|
+
RES_E_UNSUPPORTED: UnsupportedMethod,
|
|
295
|
+
RES_E_AUTO_TRADING_DISABLED: AutoTradingDisabled,
|
|
296
|
+
RES_E_INTERNAL_FAIL_SEND: InternalFailSend,
|
|
297
|
+
RES_E_INTERNAL_FAIL_RECEIVE: InternalFailReceive,
|
|
298
|
+
RES_E_INTERNAL_FAIL_INIT: InternalFailInit,
|
|
299
|
+
RES_E_INTERNAL_FAIL_CONNECT: InternalFailConnect,
|
|
300
|
+
RES_E_INTERNAL_FAIL_TIMEOUT: InternalFailTimeout,
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def raise_mt5_error(message: Optional[str] = None):
|
|
305
|
+
"""Raises an exception based on the given error code.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
message: An optional custom error message.
|
|
309
|
+
|
|
310
|
+
Raises:
|
|
311
|
+
MT5TerminalError: A specific exception based on the error code.
|
|
312
|
+
"""
|
|
313
|
+
if message and isinstance(message, Exception):
|
|
314
|
+
message = str(message)
|
|
315
|
+
exception = _ERROR_CODE_TO_EXCEPTION_.get(MT5.last_error()[0])
|
|
316
|
+
if exception is not None:
|
|
317
|
+
raise exception(f"{message or MT5.last_error()[1]}")
|
|
318
|
+
else:
|
|
319
|
+
raise Exception(f"{message or MT5.last_error()[1]}")
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
_ORDER_FILLING_TYPE_ = "https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties#enum_order_type_filling"
|
|
323
|
+
_ORDER_TYPE_ = "https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties#enum_order_type"
|
|
324
|
+
_POSITION_IDENTIFIER_ = "https://www.mql5.com/en/docs/constants/tradingconstants/positionproperties#enum_position_property_integer"
|
|
325
|
+
_FIFO_RULE_ = "https://www.mql5.com/en/docs/constants/environment_state/accountinformation#enum_account_info_integer"
|
|
326
|
+
|
|
327
|
+
_TRADE_RETCODE_MESSAGES_ = {
|
|
328
|
+
10004: "Requote: The price has changed, please try again",
|
|
329
|
+
10006: "Request rejected",
|
|
330
|
+
10007: "Request canceled by trader",
|
|
331
|
+
10008: "Order placed",
|
|
332
|
+
10009: "Request completed",
|
|
333
|
+
10010: "Only part of the request was completed",
|
|
334
|
+
10011: "Request processing error",
|
|
335
|
+
10012: "Request canceled by timeout",
|
|
336
|
+
10013: "Invalid request",
|
|
337
|
+
10014: "Invalid volume in the request",
|
|
338
|
+
10015: "Invalid price in the request",
|
|
339
|
+
10016: "Invalid stops in the request",
|
|
340
|
+
10017: "Trade is disabled",
|
|
341
|
+
10018: "Market is closed",
|
|
342
|
+
10019: "Insufficient funds to complete the request",
|
|
343
|
+
10020: "Prices changed",
|
|
344
|
+
10021: "No quotes to process the request",
|
|
345
|
+
10022: "Invalid order expiration date in the request",
|
|
346
|
+
10023: "Order state changed",
|
|
347
|
+
10024: "Too many requests, please try again later",
|
|
348
|
+
10025: "No changes in request",
|
|
349
|
+
10026: "Autotrading disabled by server",
|
|
350
|
+
10027: "Autotrading disabled by client terminal",
|
|
351
|
+
10028: "Request locked for processing",
|
|
352
|
+
10029: "Order or position frozen",
|
|
353
|
+
10030: "Invalid order filling type: see" + " " + _ORDER_FILLING_TYPE_,
|
|
354
|
+
10031: "No connection with the trade server",
|
|
355
|
+
10032: "Operation allowed only for live accounts",
|
|
356
|
+
10033: "The number of pending orders has reached the limit",
|
|
357
|
+
10034: "Order/position volume limit for the symbol reached",
|
|
358
|
+
10035: "Incorrect or prohibited order type: see" + " " + _ORDER_TYPE_,
|
|
359
|
+
10036: "Position with the specified ID has already been closed: see"
|
|
360
|
+
+ " "
|
|
361
|
+
+ _POSITION_IDENTIFIER_,
|
|
362
|
+
10038: "Close volume exceeds the current position volume",
|
|
363
|
+
10039: "A close order already exists for this position",
|
|
364
|
+
10040: "Maximum number of open positions reached",
|
|
365
|
+
10041: "Pending order activation rejected, order canceled",
|
|
366
|
+
10042: "Only long positions are allowed",
|
|
367
|
+
10043: "Only short positions are allowed",
|
|
368
|
+
10044: "Only position closing is allowed",
|
|
369
|
+
10045: "Position closing allowed only by FIFO rule: see" + " " + _FIFO_RULE_,
|
|
370
|
+
10046: "Opposite positions on this symbol are disabled",
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def trade_retcode_message(code, display=False, add_msg=""):
|
|
375
|
+
"""
|
|
376
|
+
Retrieves a user-friendly message corresponding to a given trade return code.
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
code (int): The trade return code to look up.
|
|
380
|
+
display (bool, optional): Whether to print the message to the console. Defaults to False.
|
|
381
|
+
|
|
382
|
+
Returns:
|
|
383
|
+
str: The message associated with the provided trade return code. If the code is not found,
|
|
384
|
+
it returns "Unknown trade error.".
|
|
385
|
+
"""
|
|
386
|
+
message = _TRADE_RETCODE_MESSAGES_.get(code, "Unknown trade error")
|
|
387
|
+
if display:
|
|
388
|
+
print(message + add_msg)
|
|
389
|
+
return message
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
_ADMIRAL_MARKETS_URL_ = "https://one.justmarkets.link/a/tufvj0xugm/registration/trader"
|
|
393
|
+
_JUST_MARKETS_URL_ = "https://one.justmarkets.link/a/tufvj0xugm/registration/trader"
|
|
394
|
+
_FTMO_URL_ = "https://trader.ftmo.com/?affiliates=JGmeuQqepAZLMcdOEQRp"
|
|
395
|
+
|
|
396
|
+
INIT_MSG = (
|
|
397
|
+
f"\n* Check your internet connection\n"
|
|
398
|
+
f"* Make sure MT5 is installed and active\n"
|
|
399
|
+
f"* Looking for a boker? See [{_ADMIRAL_MARKETS_URL_}] "
|
|
400
|
+
f"or [{_JUST_MARKETS_URL_}]\n"
|
|
401
|
+
f"* Looking for a prop firm? See [{_FTMO_URL_}]\n"
|
|
402
|
+
)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Overview
|
|
3
|
+
========
|
|
4
|
+
|
|
5
|
+
The Models Module provides a collection of quantitative models for financial analysis and decision-making.
|
|
6
|
+
It includes tools for portfolio optimization and natural language processing (NLP) to extract insights
|
|
7
|
+
from financial text data. This module is designed to support quantitative trading strategies by
|
|
8
|
+
providing a robust framework for financial modeling.
|
|
9
|
+
|
|
10
|
+
Features
|
|
11
|
+
========
|
|
12
|
+
|
|
13
|
+
- **Portfolio Optimization**: Implements techniques to optimize portfolio allocation, helping to maximize returns and manage risk.
|
|
14
|
+
- **Natural Language Processing (NLP)**: Provides tools for analyzing financial news and other text-based data to gauge market sentiment.
|
|
15
|
+
- **Extensible Design**: Structured to allow for the easy addition of new quantitative models and algorithms.
|
|
16
|
+
|
|
17
|
+
Components
|
|
18
|
+
==========
|
|
19
|
+
|
|
20
|
+
- **Optimization**: Contains portfolio optimization models and related utilities.
|
|
21
|
+
- **NLP**: Includes tools and models for natural language processing tailored for financial applications.
|
|
22
|
+
|
|
23
|
+
Examples
|
|
24
|
+
========
|
|
25
|
+
|
|
26
|
+
>>> from bbstrader.models import optimized_weights
|
|
27
|
+
>>> # Assuming 'returns' is a DataFrame of asset returns
|
|
28
|
+
>>> optimal_weights = optimized_weights(returns=returns)
|
|
29
|
+
>>> print(optimal_weights)
|
|
30
|
+
|
|
31
|
+
Notes
|
|
32
|
+
=====
|
|
33
|
+
|
|
34
|
+
This module is focused on providing the analytical tools for quantitative analysis. The models
|
|
35
|
+
can be integrated into trading strategies to provide data-driven signals.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
from bbstrader.models.optimization import * # noqa: F403
|
|
39
|
+
from bbstrader.models.nlp import * # noqa: F403
|