bbstrader 0.1.94__py3-none-any.whl → 0.2.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.

Files changed (38) hide show
  1. bbstrader/__ini__.py +9 -9
  2. bbstrader/btengine/__init__.py +7 -7
  3. bbstrader/btengine/backtest.py +30 -26
  4. bbstrader/btengine/data.py +100 -79
  5. bbstrader/btengine/event.py +2 -1
  6. bbstrader/btengine/execution.py +18 -16
  7. bbstrader/btengine/performance.py +11 -7
  8. bbstrader/btengine/portfolio.py +35 -36
  9. bbstrader/btengine/strategy.py +119 -94
  10. bbstrader/config.py +14 -8
  11. bbstrader/core/__init__.py +0 -0
  12. bbstrader/core/data.py +22 -0
  13. bbstrader/core/utils.py +57 -0
  14. bbstrader/ibkr/__init__.py +0 -0
  15. bbstrader/ibkr/utils.py +0 -0
  16. bbstrader/metatrader/__init__.py +5 -5
  17. bbstrader/metatrader/account.py +117 -121
  18. bbstrader/metatrader/rates.py +83 -80
  19. bbstrader/metatrader/risk.py +23 -37
  20. bbstrader/metatrader/trade.py +169 -140
  21. bbstrader/metatrader/utils.py +3 -3
  22. bbstrader/models/__init__.py +5 -5
  23. bbstrader/models/factors.py +280 -0
  24. bbstrader/models/ml.py +1092 -0
  25. bbstrader/models/optimization.py +31 -28
  26. bbstrader/models/{portfolios.py → portfolio.py} +64 -46
  27. bbstrader/models/risk.py +15 -9
  28. bbstrader/trading/__init__.py +2 -2
  29. bbstrader/trading/execution.py +252 -164
  30. bbstrader/trading/scripts.py +8 -4
  31. bbstrader/trading/strategies.py +79 -66
  32. bbstrader/tseries.py +482 -107
  33. {bbstrader-0.1.94.dist-info → bbstrader-0.2.1.dist-info}/LICENSE +1 -1
  34. {bbstrader-0.1.94.dist-info → bbstrader-0.2.1.dist-info}/METADATA +6 -1
  35. bbstrader-0.2.1.dist-info/RECORD +37 -0
  36. bbstrader-0.1.94.dist-info/RECORD +0 -32
  37. {bbstrader-0.1.94.dist-info → bbstrader-0.2.1.dist-info}/WHEEL +0 -0
  38. {bbstrader-0.1.94.dist-info → bbstrader-0.2.1.dist-info}/top_level.txt +0 -0
@@ -1,26 +1,21 @@
1
- import pandas as pd
2
- import MetaTrader5 as Mt5
3
1
  from datetime import datetime
4
- from typing import Union, Optional
5
- from bbstrader.metatrader.utils import (
6
- raise_mt5_error,
7
- TimeFrame,
8
- TIMEFRAMES
9
- )
10
- from bbstrader.metatrader.account import Account
11
- from bbstrader.metatrader.account import AMG_EXCHANGES
12
- from bbstrader.metatrader.account import check_mt5_connection
13
- from pandas.tseries.offsets import CustomBusinessDay
2
+ from typing import Optional, Union
3
+
4
+ import MetaTrader5 as Mt5
5
+ import pandas as pd
6
+ from exchange_calendars import get_calendar, get_calendar_names
14
7
  from pandas.tseries.holiday import USFederalHolidayCalendar
15
- from exchange_calendars import(
16
- get_calendar,
17
- get_calendar_names
18
- )
8
+ from pandas.tseries.offsets import CustomBusinessDay
9
+
10
+ from bbstrader.metatrader.account import AMG_EXCHANGES, Account, check_mt5_connection
11
+ from bbstrader.metatrader.utils import TIMEFRAMES, TimeFrame, raise_mt5_error
19
12
 
20
13
  __all__ = [
21
- 'Rates',
22
- 'download_historical_data',
23
- 'get_data_from_pos'
14
+ 'Rates',
15
+ 'download_historical_data',
16
+ 'get_data_from_pos',
17
+ 'get_data_from_date'
18
+
24
19
  ]
25
20
 
26
21
  MAX_BARS = 10_000_000
@@ -40,20 +35,20 @@ IDX_CALENDARS = {
40
35
  }
41
36
 
42
37
  COMD_CALENDARS = {
43
- "Energies" : "us_futures",
44
- "Metals" : "us_futures",
45
- "Agricultures" : "CBOT",
46
- "Bonds": {"USD" : "CBOT", "EUR": "EUREX"},
38
+ "Energies": "us_futures",
39
+ "Metals": "us_futures",
40
+ "Agricultures": "CBOT",
41
+ "Bonds": {"USD": "CBOT", "EUR": "EUREX"},
47
42
  }
48
43
 
49
44
  CALENDARS = {
50
- "FX" : "us_futures",
51
- "STK" : AMG_EXCHANGES,
52
- "ETF" : AMG_EXCHANGES,
53
- "IDX" : IDX_CALENDARS,
54
- "COMD" : COMD_CALENDARS,
45
+ "FX": "us_futures",
46
+ "STK": AMG_EXCHANGES,
47
+ "ETF": AMG_EXCHANGES,
48
+ "IDX": IDX_CALENDARS,
49
+ "COMD": COMD_CALENDARS,
55
50
  "CRYPTO": "24/7",
56
- "FUT" : None,
51
+ "FUT": None,
57
52
  }
58
53
 
59
54
  SESSION_TIMEFRAMES = [
@@ -78,7 +73,7 @@ class Rates(object):
78
73
  is set to a value that is greater than the number of bars you want to retrieve
79
74
  or just set it to Unlimited.
80
75
  In your MT5 terminal, go to `Tools` -> `Options` -> `Charts` -> `Max bars in chart`.
81
-
76
+
82
77
  2. The `open, high, low, close, adjclose, returns,
83
78
  volume` properties returns data in Broker's timezone by default.
84
79
 
@@ -97,7 +92,7 @@ class Rates(object):
97
92
  self,
98
93
  symbol: str,
99
94
  timeframe: TimeFrame = 'D1',
100
- start_pos: Union[int , str] = 0,
95
+ start_pos: Union[int, str] = 0,
101
96
  count: Optional[int] = MAX_BARS,
102
97
  session_duration: Optional[float] = None,
103
98
  **kwargs
@@ -121,7 +116,6 @@ class Rates(object):
121
116
  For `session_duration` check your broker symbols details
122
117
  """
123
118
  self.symbol = symbol
124
- tf = kwargs.get('time_frame')
125
119
  self.time_frame = self._validate_time_frame(timeframe)
126
120
  self.sd = session_duration
127
121
  self.start_pos = self._get_start_pos(start_pos, timeframe)
@@ -132,7 +126,7 @@ class Rates(object):
132
126
 
133
127
  def _mt5_initialized(self, **kwargs):
134
128
  check_mt5_connection(**kwargs)
135
-
129
+
136
130
  def _get_start_pos(self, index, time_frame):
137
131
  if isinstance(index, int):
138
132
  start_pos = index
@@ -182,9 +176,9 @@ class Rates(object):
182
176
  return TIMEFRAMES[time_frame]
183
177
 
184
178
  def _fetch_data(
185
- self,
179
+ self,
186
180
  start: Union[int, datetime, pd.Timestamp],
187
- count: Union[int, datetime, pd.Timestamp],
181
+ count: Union[int, datetime, pd.Timestamp],
188
182
  lower_colnames=False, utc=False,
189
183
  ) -> Union[pd.DataFrame, None]:
190
184
  """Fetches data from MT5 and returns a DataFrame or None."""
@@ -193,17 +187,17 @@ class Rates(object):
193
187
  rates = Mt5.copy_rates_from_pos(
194
188
  self.symbol, self.time_frame, start, count
195
189
  )
196
- elif (
197
- isinstance(start, (datetime, pd.Timestamp)) and
190
+ elif (
191
+ isinstance(start, (datetime, pd.Timestamp)) and
198
192
  isinstance(count, int)
199
- ):
193
+ ):
200
194
  rates = Mt5.copy_rates_from(
201
195
  self.symbol, self.time_frame, start, count
202
196
  )
203
197
  elif (
204
- isinstance(start, (datetime, pd.Timestamp)) and
198
+ isinstance(start, (datetime, pd.Timestamp)) and
205
199
  isinstance(count, (datetime, pd.Timestamp))
206
- ):
200
+ ):
207
201
  rates = Mt5.copy_rates_range(
208
202
  self.symbol, self.time_frame, start, count
209
203
  )
@@ -215,7 +209,7 @@ class Rates(object):
215
209
  except Exception as e:
216
210
  raise_mt5_error(e)
217
211
 
218
- def _format_dataframe(self, df: pd.DataFrame,
212
+ def _format_dataframe(self, df: pd.DataFrame,
219
213
  lower_colnames=False, utc=False) -> pd.DataFrame:
220
214
  """Formats the raw MT5 data into a standardized DataFrame."""
221
215
  df = df.copy()
@@ -223,7 +217,6 @@ class Rates(object):
223
217
  df.columns = ['Date', 'Open', 'High', 'Low', 'Close', 'Volume']
224
218
  df['Adj Close'] = df['Close']
225
219
  df = df[['Date', 'Open', 'High', 'Low', 'Close', 'Adj Close', 'Volume']]
226
- #df = df.columns.rename(str.lower).str.replace(' ', '_')
227
220
  df['Date'] = pd.to_datetime(df['Date'], unit='s', utc=utc)
228
221
  df.set_index('Date', inplace=True)
229
222
  if lower_colnames:
@@ -246,19 +239,23 @@ class Rates(object):
246
239
  calendar = get_calendar(exchange, side='right')
247
240
  break
248
241
  elif symbol_type == 'IDX':
249
- calendar = get_calendar(CALENDARS[symbol_type][currencies['mc']], side='right')
242
+ calendar = get_calendar(
243
+ CALENDARS[symbol_type][currencies['mc']], side='right')
250
244
  elif symbol_type == 'COMD':
251
245
  for commodity in CALENDARS[symbol_type]:
252
246
  if commodity in s_info.path:
253
- calendar = get_calendar(CALENDARS[symbol_type][commodity], side='right')
247
+ calendar = get_calendar(
248
+ CALENDARS[symbol_type][commodity], side='right')
254
249
  elif symbol_type == 'FUT':
255
250
  if 'Index' in s_info.path:
256
- calendar = get_calendar(CALENDARS['IDX'][currencies['mc']], side='right')
251
+ calendar = get_calendar(
252
+ CALENDARS['IDX'][currencies['mc']], side='right')
257
253
  else:
258
254
  for commodity, cal in COMD_CALENDARS.items():
259
255
  if self.symbol in self.__account.get_future_symbols(category=commodity):
260
256
  if commodity == 'Bonds':
261
- calendar = get_calendar(cal[currencies['mc']], side='right')
257
+ calendar = get_calendar(
258
+ cal[currencies['mc']], side='right')
262
259
  else:
263
260
  calendar = get_calendar(cal, side='right')
264
261
  else:
@@ -274,7 +271,7 @@ class Rates(object):
274
271
  index_name = df.index.name
275
272
  if fill_na:
276
273
  if isinstance(fill_na, bool):
277
- method = 'nearest'
274
+ method = 'nearest'
278
275
  if isinstance(fill_na, str):
279
276
  method = fill_na
280
277
  df = df.reindex(valid_sessions, method=method)
@@ -284,15 +281,15 @@ class Rates(object):
284
281
  else:
285
282
  df = df[df.index.isin(valid_sessions)]
286
283
  return df
287
-
284
+
288
285
  def _check_filter(self, filter, utc):
289
286
  if filter and self.time_frame not in SESSION_TIMEFRAMES and not utc:
290
287
  utc = True
291
288
  elif filter and self.time_frame in SESSION_TIMEFRAMES and utc:
292
289
  utc = False
293
290
  return utc
294
-
295
- def get_rates_from_pos(self, filter=False, fill_na=False,
291
+
292
+ def get_rates_from_pos(self, filter=False, fill_na=False,
296
293
  lower_colnames=False, utc=False
297
294
  ) -> Union[pd.DataFrame, None]:
298
295
  """
@@ -311,7 +308,7 @@ class Rates(object):
311
308
  Returns:
312
309
  Union[pd.DataFrame, None]: A DataFrame containing historical
313
310
  data if successful, otherwise None.
314
-
311
+
315
312
  Raises:
316
313
  ValueError: If `start_pos` or `count` is not provided during
317
314
  initialization.
@@ -332,8 +329,8 @@ class Rates(object):
332
329
  if filter:
333
330
  return self._filter_data(df, fill_na=fill_na)
334
331
  return df
335
-
336
- def get_rates_from(self, date_from: datetime | pd.Timestamp, count: int=MAX_BARS,
332
+
333
+ def get_rates_from(self, date_from: datetime | pd.Timestamp, count: int = MAX_BARS,
337
334
  filter=False, fill_na=False, lower_colnames=False, utc=False) -> Union[pd.DataFrame, None]:
338
335
  """
339
336
  Retrieves historical data within a specified date range.
@@ -341,9 +338,9 @@ class Rates(object):
341
338
  Args:
342
339
  date_from : Starting date for data retrieval.
343
340
  The data will be retrieved from this date going to the past.
344
-
341
+
345
342
  count : Number of bars to retrieve.
346
-
343
+
347
344
  filter : See `Rates.get_historical_data` for more details.
348
345
  fill_na : See `Rates.get_historical_data` for more details.
349
346
  lower_colnames : If True, the column names will be converted to lowercase.
@@ -355,7 +352,8 @@ class Rates(object):
355
352
  data if successful, otherwise None.
356
353
  """
357
354
  utc = self._check_filter(filter, utc)
358
- df = self._fetch_data(date_from, count, lower_colnames=lower_colnames, utc=utc)
355
+ df = self._fetch_data(
356
+ date_from, count, lower_colnames=lower_colnames, utc=utc)
359
357
  if df is None:
360
358
  return None
361
359
  if filter:
@@ -365,15 +363,15 @@ class Rates(object):
365
363
  @property
366
364
  def open(self):
367
365
  return self.__data['Open']
368
-
366
+
369
367
  @property
370
368
  def high(self):
371
369
  return self.__data['High']
372
-
370
+
373
371
  @property
374
372
  def low(self):
375
373
  return self.__data['Low']
376
-
374
+
377
375
  @property
378
376
  def close(self):
379
377
  return self.__data['Close']
@@ -381,7 +379,7 @@ class Rates(object):
381
379
  @property
382
380
  def adjclose(self):
383
381
  return self.__data['Adj Close']
384
-
382
+
385
383
  @property
386
384
  def returns(self):
387
385
  """
@@ -396,10 +394,10 @@ class Rates(object):
396
394
  and `not percentage change`. If you need the percentage change, multiply these values by 100.
397
395
  """
398
396
  data = self.__data.copy()
399
- data['Returns'] = data['Adj Close'].pct_change()
397
+ data['Returns'] = data['Adj Close'].pct_change()
400
398
  data = data.dropna()
401
399
  return data['Returns']
402
-
400
+
403
401
  @property
404
402
  def volume(self):
405
403
  return self.__data['Volume']
@@ -419,17 +417,17 @@ class Rates(object):
419
417
 
420
418
  Args:
421
419
  date_from : Starting date for data retrieval.
422
-
420
+
423
421
  date_to : Ending date for data retrieval.
424
422
  Defaults to the current time.
425
-
423
+
426
424
  utc : If True, the data will be in UTC timezone.
427
425
  Defaults to False.
428
-
426
+
429
427
  filter : If True, the data will be filtered based
430
428
  on the trading sessions for the symbol.
431
429
  This is use when we want to use the data for backtesting using Zipline.
432
-
430
+
433
431
  fill_na : If True, the data will be filled with the nearest value.
434
432
  This is use only when `filter` is True and time frame is "1m" or "D1",
435
433
  this is because we use ``calendar.minutes_in_range`` or ``calendar.sessions_in_range``
@@ -438,24 +436,24 @@ class Rates(object):
438
436
  because the data from MT5 will have approximately the same number of rows as the
439
437
  number of trading days or minute in the exchange calendar, so we can fill the missing
440
438
  data with the nearest value.
441
-
439
+
442
440
  But for other time frames, the data will be reindexed with the exchange calendar
443
441
  because the data from MT5 will have more rows than the number of trading days or minute
444
442
  in the exchange calendar. So we only take the data that is in the range of the exchange
445
443
  calendar sessions or minutes.
446
-
444
+
447
445
  lower_colnames : If True, the column names will be converted to lowercase.
448
-
446
+
449
447
  save_csv : File path to save the data as a CSV.
450
448
  If None, the data won't be saved.
451
449
 
452
450
  Returns:
453
451
  Union[pd.DataFrame, None]: A DataFrame containing historical data
454
452
  if successful, otherwise None.
455
-
453
+
456
454
  Raises:
457
455
  ValueError: If the starting date is greater than the ending date.
458
-
456
+
459
457
  Notes:
460
458
  The `filter` for this method can be use only for Admira Markets Group (AMG) symbols.
461
459
  The Datetime for this method is in Local timezone by default.
@@ -470,13 +468,15 @@ class Rates(object):
470
468
  if df is None:
471
469
  return None
472
470
  if filter:
473
- df = self._filter_data(df, date_from=date_from, date_to=date_to, fill_na=fill_na)
471
+ df = self._filter_data(
472
+ df, date_from=date_from, date_to=date_to, fill_na=fill_na)
474
473
  if save_csv:
475
474
  df.to_csv(f"{self.symbol}.csv")
476
475
  return df
477
476
 
478
- def download_historical_data(symbol, timeframe, date_from,
479
- date_to=pd.Timestamp.now(),lower_colnames=True,
477
+
478
+ def download_historical_data(symbol, timeframe, date_from,
479
+ date_to=pd.Timestamp.now(), lower_colnames=True,
480
480
  utc=False, filter=False, fill_na=False, save_csv=False, **kwargs):
481
481
  """Download historical data from MetaTrader 5 terminal.
482
482
  See `Rates.get_historical_data` for more details.
@@ -492,23 +492,26 @@ def download_historical_data(symbol, timeframe, date_from,
492
492
  )
493
493
  return data
494
494
 
495
- def get_data_from_pos(symbol, timeframe, start_pos=0, fill_na=False,
495
+
496
+ def get_data_from_pos(symbol, timeframe, start_pos=0, fill_na=False,
496
497
  count=MAX_BARS, lower_colnames=False, utc=False, filter=False,
497
- session_duration=23.0, **kwargs):
498
+ session_duration=23.0, **kwargs):
498
499
  """Get historical data from a specific position.
499
500
  See `Rates.get_rates_from_pos` for more details.
500
501
  """
501
- rates = Rates(symbol, timeframe, start_pos, count, session_duration, **kwargs)
502
+ rates = Rates(symbol, timeframe, start_pos,
503
+ count, session_duration, **kwargs)
502
504
  data = rates.get_rates_from_pos(filter=filter, fill_na=fill_na,
503
505
  lower_colnames=lower_colnames, utc=utc)
504
506
  return data
505
507
 
506
- def get_data_from_date(symbol, timeframe, date_from, count=MAX_BARS, fill_na=False,
507
- lower_colnames=False, utc=False, filter=False, **kwargs):
508
+
509
+ def get_data_from_date(symbol, timeframe, date_from, count=MAX_BARS, fill_na=False,
510
+ lower_colnames=False, utc=False, filter=False, **kwargs):
508
511
  """Get historical data from a specific date.
509
512
  See `Rates.get_rates_from` for more details.
510
513
  """
511
514
  rates = Rates(symbol, timeframe, **kwargs)
512
515
  data = rates.get_rates_from(date_from, count, filter=filter, fill_na=fill_na,
513
516
  lower_colnames=lower_colnames, utc=utc)
514
- return data
517
+ return data
@@ -1,25 +1,13 @@
1
1
  import random
2
- import re
3
- import numpy as np
4
- from scipy.stats import norm
5
2
  from datetime import datetime
3
+ from typing import Any, Dict, Optional, Union
4
+
6
5
  import MetaTrader5 as Mt5
6
+ from scipy.stats import norm
7
+
7
8
  from bbstrader.metatrader.account import Account
8
9
  from bbstrader.metatrader.rates import Rates
9
- from bbstrader.metatrader.utils import (
10
- TIMEFRAMES,
11
- raise_mt5_error,
12
- TimeFrame
13
- )
14
- from typing import (
15
- List,
16
- Dict,
17
- Optional,
18
- Literal,
19
- Union,
20
- Any
21
- )
22
-
10
+ from bbstrader.metatrader.utils import TIMEFRAMES, TimeFrame
23
11
 
24
12
  _COMMD_SUPPORTED_ = [
25
13
  "GOLD", "XAUEUR", "SILVER", "BRENT", "CRUDOIL", "WTI", "UKOIL",
@@ -36,6 +24,7 @@ _ADMIRAL_MARKETS_FUTURES_ = [
36
24
 
37
25
  __all__ = ['RiskManagement']
38
26
 
27
+
39
28
  class RiskManagement(Account):
40
29
  """
41
30
  The RiskManagement class provides foundational
@@ -118,7 +107,7 @@ class RiskManagement(Account):
118
107
  tp (int, optional): Take Profit in points, Must be a positive number.
119
108
  be (int, optional): Break Even in points, Must be a positive number.
120
109
  rr (float, optional): Risk reward ratio, Must be a positive number. Defaults to 1.5.
121
-
110
+
122
111
  See `bbstrader.metatrader.account.check_mt5_connection()` for more details on how to connect to MT5 terminal.
123
112
  """
124
113
  super().__init__(**kwargs)
@@ -137,7 +126,8 @@ class RiskManagement(Account):
137
126
  if time_frame not in TIMEFRAMES:
138
127
  raise ValueError("Unsupported time frame {}".format(time_frame))
139
128
  if var_time_frame not in TIMEFRAMES:
140
- raise ValueError("Unsupported time frame {}".format(var_time_frame))
129
+ raise ValueError(
130
+ "Unsupported time frame {}".format(var_time_frame))
141
131
 
142
132
  self.kwargs = kwargs
143
133
  self.symbol = symbol
@@ -167,15 +157,15 @@ class RiskManagement(Account):
167
157
  @dailydd.setter
168
158
  def dailydd(self, value: float):
169
159
  self.daily_dd = value
170
-
160
+
171
161
  @property
172
162
  def maxrisk(self) -> float:
173
163
  return self.max_risk
174
-
164
+
175
165
  @maxrisk.setter
176
166
  def maxrisk(self, value: float):
177
167
  self.max_risk = value
178
-
168
+
179
169
  def _convert_time_frame(self, tf: str) -> int:
180
170
  """Convert time frame to minutes"""
181
171
  if tf == 'D1':
@@ -236,7 +226,7 @@ class RiskManagement(Account):
236
226
  decimal_index = value_str.index('.')
237
227
  num_digits = len(value_str) - decimal_index - 1
238
228
  return num_digits
239
-
229
+
240
230
  elif value_str == '1.0':
241
231
  return 0
242
232
  else:
@@ -280,7 +270,7 @@ class RiskManagement(Account):
280
270
  """
281
271
  minutes = self.get_minutes()
282
272
  tf_int = self._convert_time_frame(self._tf)
283
- interval = round((minutes / tf_int) * 252)
273
+ interval = round((minutes / tf_int) * 252)
284
274
 
285
275
  rate = Rates(self.symbol, self._tf, 0, interval, **self.kwargs)
286
276
  returns = rate.returns*100
@@ -334,7 +324,7 @@ class RiskManagement(Account):
334
324
  """
335
325
  minutes = self.get_minutes()
336
326
  tf_int = self._convert_time_frame(tf)
337
- interval = round((minutes / tf_int) * 252)
327
+ interval = round((minutes / tf_int) * 252)
338
328
 
339
329
  rate = Rates(self.symbol, tf, 0, interval, **self.kwargs)
340
330
  returns = rate.returns*100
@@ -418,15 +408,13 @@ class RiskManagement(Account):
418
408
 
419
409
  Returns:
420
410
  Dict[str, Union[int, float, Any]]: A dictionary containing the following keys:
421
-
411
+
422
412
  - `'currency_risk'`: Dollar amount risk on a single trade.
423
413
  - `'trade_loss'`: Loss value per tick in dollars.
424
414
  - `'trade_profit'`: Profit value per tick in dollars.
425
415
  - `'volume'`: Contract size multiplied by the average price.
426
416
  - `'lot'`: Lot size per trade.
427
417
  """
428
-
429
- account_info = self.get_account_info()
430
418
  s_info = self.symbol_info
431
419
 
432
420
  laverage = self.get_leverage(self.account_leverage)
@@ -435,9 +423,9 @@ class RiskManagement(Account):
435
423
  av_price = (s_info.bid + s_info.ask)/2
436
424
  trade_risk = self.get_trade_risk()
437
425
  symbol_type = self.get_symbol_type(self.symbol)
438
- FX = symbol_type == 'FX'
439
- COMD = symbol_type == 'COMD'
440
- FUT = symbol_type == 'FUT'
426
+ FX = symbol_type == 'FX'
427
+ COMD = symbol_type == 'COMD'
428
+ FUT = symbol_type == 'FUT'
441
429
  CRYPTO = symbol_type == 'CRYPTO'
442
430
  if COMD:
443
431
  supported = _COMMD_SUPPORTED_
@@ -483,16 +471,15 @@ class RiskManagement(Account):
483
471
  tick_value_loss = tick_value_loss / contract_size
484
472
  tick_value_profit = tick_value_profit / contract_size
485
473
  if (tick_value == 0
486
- or tick_value_loss == 0
487
- or tick_value_profit == 0
488
- ):
474
+ or tick_value_loss == 0
475
+ or tick_value_profit == 0
476
+ ):
489
477
  raise ValueError(
490
478
  f"""The Tick Values for {self.symbol} is 0.0
491
479
  We can not procced with currency risk calculation
492
480
  Please check your Broker trade conditions
493
481
  and symbol specifications for {self.symbol}"""
494
482
  )
495
- point = float(s_info.point)
496
483
 
497
484
  # Case where the stop loss is given
498
485
  if self.sl is not None:
@@ -580,7 +567,6 @@ class RiskManagement(Account):
580
567
  """
581
568
  trade_loss = currency_risk/sl
582
569
  trade_profit = (currency_risk*self.rr)/(sl*self.rr)
583
- laverage = self.get_account_info().leverage
584
570
  av_price = (self.symbol_info.bid + self.symbol_info.ask)/2
585
571
  _lot = round(trade_loss/(size*loss), 2)
586
572
  lot = self._check_lot(_lot)
@@ -652,7 +638,7 @@ class RiskManagement(Account):
652
638
  margin = Mt5.order_calc_margin(
653
639
  action, self.symbol, volume_min, av_price
654
640
  )
655
- if margin == None:
641
+ if margin is None:
656
642
  return AL
657
643
  try:
658
644
  leverage = (