bbstrader 0.1.5__py3-none-any.whl → 0.1.6__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.
- bbstrader/btengine/backtest.py +10 -7
- bbstrader/btengine/data.py +22 -11
- bbstrader/btengine/event.py +4 -3
- bbstrader/btengine/execution.py +1 -1
- bbstrader/btengine/strategy.py +3 -1
- bbstrader/metatrader/account.py +14 -2
- bbstrader/metatrader/rates.py +30 -12
- bbstrader/metatrader/trade.py +10 -7
- bbstrader/metatrader/utils.py +3 -2
- bbstrader/trading/execution.py +24 -12
- {bbstrader-0.1.5.dist-info → bbstrader-0.1.6.dist-info}/METADATA +1 -1
- bbstrader-0.1.6.dist-info/RECORD +28 -0
- {bbstrader-0.1.5.dist-info → bbstrader-0.1.6.dist-info}/WHEEL +1 -1
- bbstrader-0.1.5.dist-info/RECORD +0 -28
- {bbstrader-0.1.5.dist-info → bbstrader-0.1.6.dist-info}/LICENSE +0 -0
- {bbstrader-0.1.5.dist-info → bbstrader-0.1.6.dist-info}/top_level.txt +0 -0
bbstrader/btengine/backtest.py
CHANGED
|
@@ -6,7 +6,6 @@ import pandas as pd
|
|
|
6
6
|
import yfinance as yf
|
|
7
7
|
from queue import Queue
|
|
8
8
|
from datetime import datetime
|
|
9
|
-
from seaborn import saturate
|
|
10
9
|
from bbstrader.btengine.data import *
|
|
11
10
|
from bbstrader.btengine.execution import *
|
|
12
11
|
from bbstrader.btengine.portfolio import Portfolio
|
|
@@ -132,7 +131,8 @@ class Backtest(object):
|
|
|
132
131
|
self.start_date,
|
|
133
132
|
self.initial_capital, **self.kwargs
|
|
134
133
|
)
|
|
135
|
-
self.execution_handler: ExecutionHandler = self.eh_cls(
|
|
134
|
+
self.execution_handler: ExecutionHandler = self.eh_cls(
|
|
135
|
+
self.events, **self.kwargs)
|
|
136
136
|
|
|
137
137
|
def _run_backtest(self):
|
|
138
138
|
"""
|
|
@@ -172,7 +172,7 @@ class Backtest(object):
|
|
|
172
172
|
self.fills += 1
|
|
173
173
|
self.portfolio.update_fill(event)
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
time.sleep(self.heartbeat)
|
|
176
176
|
|
|
177
177
|
def _output_performance(self):
|
|
178
178
|
"""
|
|
@@ -788,10 +788,10 @@ def _run_sma_backtest(
|
|
|
788
788
|
"quantity": quantity,
|
|
789
789
|
"hmm_end": "2009-12-31",
|
|
790
790
|
"hmm_tiker": "^GSPC",
|
|
791
|
-
"yf_start": "2010-01-
|
|
791
|
+
"yf_start": "2010-01-04",
|
|
792
792
|
"hmm_start": "1990-01-01",
|
|
793
|
-
"
|
|
794
|
-
"
|
|
793
|
+
"mt5_start": datetime(2010, 1, 4),
|
|
794
|
+
"mt5_end": datetime(2023, 1, 1),
|
|
795
795
|
"backtester_class": SMAStrategyBacktester,
|
|
796
796
|
"data_handler": MT5HistoricDataHandler
|
|
797
797
|
}
|
|
@@ -892,7 +892,10 @@ def run_backtest(
|
|
|
892
892
|
quantity=test_quantity
|
|
893
893
|
)
|
|
894
894
|
else:
|
|
895
|
-
|
|
895
|
+
if exc_handler is None:
|
|
896
|
+
execution_handler = SimulatedExecutionHandler
|
|
897
|
+
else:
|
|
898
|
+
execution_handler = exc_handler
|
|
896
899
|
engine = Backtest(
|
|
897
900
|
symbol_list, initial_capital, heartbeat, start_date,
|
|
898
901
|
data_handler, execution_handler, strategy, **kwargs
|
bbstrader/btengine/data.py
CHANGED
|
@@ -8,6 +8,7 @@ from queue import Queue
|
|
|
8
8
|
from abc import ABCMeta, abstractmethod
|
|
9
9
|
from bbstrader.metatrader.rates import Rates
|
|
10
10
|
from bbstrader.btengine.event import MarketEvent
|
|
11
|
+
from datetime import datetime
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
__all__ = [
|
|
@@ -260,7 +261,7 @@ class HistoricCSVDataHandler(BaseCSVDataHandler):
|
|
|
260
261
|
csv_dir = kwargs.get("csv_dir")
|
|
261
262
|
super().__init__(events, symbol_list, csv_dir)
|
|
262
263
|
|
|
263
|
-
|
|
264
|
+
|
|
264
265
|
class MT5HistoricDataHandler(BaseCSVDataHandler):
|
|
265
266
|
"""
|
|
266
267
|
Downloads historical data from MetaTrader 5 (MT5) and provides
|
|
@@ -281,19 +282,16 @@ class MT5HistoricDataHandler(BaseCSVDataHandler):
|
|
|
281
282
|
symbol_list (List[str]): A list of symbol strings to download data for.
|
|
282
283
|
**kwargs: Keyword arguments for data retrieval:
|
|
283
284
|
time_frame (str): MT5 time frame (e.g., 'D1' for daily).
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
If it set to `str`, it must be in 'YYYY-MM-DD' format and
|
|
287
|
-
session_duration (int | float): Number of trading hours per day.
|
|
285
|
+
mt5_start (datetime): Start date for historical data.
|
|
286
|
+
mt5_end (datetime): End date for historical data.
|
|
288
287
|
mt5_data (str): Directory for storing data (default: 'mt5_data').
|
|
289
288
|
|
|
290
289
|
Note:
|
|
291
290
|
Requires a working connection to an MT5 terminal.
|
|
292
291
|
"""
|
|
293
292
|
self.tf = kwargs.get('time_frame', 'D1')
|
|
294
|
-
self.
|
|
295
|
-
self.
|
|
296
|
-
self.sd = kwargs.get('session_duration', 6.5)
|
|
293
|
+
self.start = kwargs.get('mt5_start')
|
|
294
|
+
self.end = kwargs.get('mt5_end', datetime.now())
|
|
297
295
|
self.data_dir = kwargs.get('mt5_data', 'mt5_data')
|
|
298
296
|
self.symbol_list = symbol_list
|
|
299
297
|
csv_dir = self._download_data(self.data_dir)
|
|
@@ -304,8 +302,10 @@ class MT5HistoricDataHandler(BaseCSVDataHandler):
|
|
|
304
302
|
data_dir.mkdir(parents=True, exist_ok=True)
|
|
305
303
|
for symbol in self.symbol_list:
|
|
306
304
|
try:
|
|
307
|
-
rate = Rates(symbol, self.tf
|
|
308
|
-
data = rate.
|
|
305
|
+
rate = Rates(symbol=symbol, time_frame=self.tf)
|
|
306
|
+
data = rate.get_historical_data(
|
|
307
|
+
date_from=self.start, date_to=self.end
|
|
308
|
+
)
|
|
309
309
|
if data is None:
|
|
310
310
|
raise ValueError(f"No data found for {symbol}")
|
|
311
311
|
data.to_csv(data_dir / f'{symbol}.csv')
|
|
@@ -359,16 +359,27 @@ class YFHistoricDataHandler(BaseCSVDataHandler):
|
|
|
359
359
|
return cache_dir
|
|
360
360
|
|
|
361
361
|
|
|
362
|
+
# TODO # Get data from EODHD
|
|
363
|
+
class EODHDHistoricDataHandler(BaseCSVDataHandler):
|
|
364
|
+
...
|
|
365
|
+
|
|
362
366
|
# TODO # Get data from FinancialModelingPrep ()
|
|
363
367
|
class FMPHistoricDataHandler(BaseCSVDataHandler):
|
|
364
368
|
...
|
|
365
369
|
|
|
366
370
|
|
|
367
371
|
class BaseFMPDataHanler(object):
|
|
372
|
+
"""
|
|
373
|
+
This will serve as the base class for all other FMP data
|
|
374
|
+
that is not historical data and does not have an OHLC structure.
|
|
375
|
+
"""
|
|
368
376
|
...
|
|
369
377
|
|
|
370
378
|
|
|
371
379
|
class FMPFundamentalDataHandler(BaseFMPDataHanler):
|
|
372
380
|
...
|
|
373
381
|
|
|
374
|
-
# TODO Add other Handlers
|
|
382
|
+
# TODO Add other Handlers for FMP
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
# TODO Add data Handlers for Interactive Brokers
|
bbstrader/btengine/event.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
+
from typing import Literal
|
|
2
3
|
|
|
3
4
|
__all__ = [
|
|
4
5
|
"Event",
|
|
@@ -150,8 +151,8 @@ class FillEvent(Event):
|
|
|
150
151
|
symbol: str,
|
|
151
152
|
exchange: str,
|
|
152
153
|
quantity: int | float,
|
|
153
|
-
direction:
|
|
154
|
-
fill_cost: int | float,
|
|
154
|
+
direction: Literal['LONG', 'SHORT', 'EXIT'],
|
|
155
|
+
fill_cost: int | float | None,
|
|
155
156
|
commission: float | None = None
|
|
156
157
|
):
|
|
157
158
|
"""
|
|
@@ -168,7 +169,7 @@ class FillEvent(Event):
|
|
|
168
169
|
symbol (str): The instrument which was filled.
|
|
169
170
|
exchange (str): The exchange where the order was filled.
|
|
170
171
|
quantity (int | float): The filled quantity.
|
|
171
|
-
direction (str): The direction of fill ('
|
|
172
|
+
direction (str): The direction of fill `('LONG', 'SHORT', 'EXIT')`
|
|
172
173
|
fill_cost (int | float): The holdings value in dollars.
|
|
173
174
|
commission (float | None): An optional commission sent from IB.
|
|
174
175
|
"""
|
bbstrader/btengine/execution.py
CHANGED
bbstrader/btengine/strategy.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from abc import ABCMeta, abstractmethod
|
|
2
|
+
from typing import Dict, Union
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
class Strategy(metaclass=ABCMeta):
|
|
@@ -22,9 +23,10 @@ class Strategy(metaclass=ABCMeta):
|
|
|
22
23
|
"""
|
|
23
24
|
|
|
24
25
|
@abstractmethod
|
|
25
|
-
def calculate_signals(self):
|
|
26
|
+
def calculate_signals(self, *args, **kwargs) -> Dict[str, Union[str, None]]:
|
|
26
27
|
"""
|
|
27
28
|
Provides the mechanisms to calculate the list of signals.
|
|
29
|
+
This methods should return a dictionary of symbols and their respective signals.
|
|
28
30
|
"""
|
|
29
31
|
raise NotImplementedError(
|
|
30
32
|
"Should implement calculate_signals()"
|
bbstrader/metatrader/account.py
CHANGED
|
@@ -555,13 +555,19 @@ class Account(object):
|
|
|
555
555
|
|
|
556
556
|
Raises:
|
|
557
557
|
MT5TerminalError: A specific exception based on the error code.
|
|
558
|
+
|
|
559
|
+
Notes:
|
|
560
|
+
The `time` property is converted to a `datetime` object using Broker server time.
|
|
558
561
|
"""
|
|
559
562
|
try:
|
|
560
563
|
symbol_info = mt5.symbol_info(symbol)
|
|
561
564
|
if symbol_info is None:
|
|
562
565
|
return None
|
|
563
566
|
else:
|
|
564
|
-
|
|
567
|
+
symbol_info_dict = symbol_info._asdict()
|
|
568
|
+
time = datetime.fromtimestamp(symbol_info.time)
|
|
569
|
+
symbol_info_dict['time'] = time
|
|
570
|
+
return SymbolInfo(**symbol_info_dict)
|
|
565
571
|
except Exception as e:
|
|
566
572
|
msg = self._symbol_info_msg(symbol)
|
|
567
573
|
raise_mt5_error(message=f"{e+msg}")
|
|
@@ -595,13 +601,19 @@ class Account(object):
|
|
|
595
601
|
|
|
596
602
|
Raises:
|
|
597
603
|
MT5TerminalError: A specific exception based on the error code.
|
|
604
|
+
|
|
605
|
+
Notes:
|
|
606
|
+
The `time` property is converted to a `datetime` object using Broker server time.
|
|
598
607
|
"""
|
|
599
608
|
try:
|
|
600
609
|
tick_info = mt5.symbol_info_tick(symbol)
|
|
601
610
|
if tick_info is None:
|
|
602
611
|
return None
|
|
603
612
|
else:
|
|
604
|
-
|
|
613
|
+
info_dict = tick_info._asdict()
|
|
614
|
+
time = datetime.fromtimestamp(tick_info.time)
|
|
615
|
+
info_dict['time'] = time
|
|
616
|
+
return TickInfo(**info_dict)
|
|
605
617
|
except Exception as e:
|
|
606
618
|
msg = self._symbol_info_msg(symbol)
|
|
607
619
|
raise_mt5_error(message=f"{e+msg}")
|
bbstrader/metatrader/rates.py
CHANGED
|
@@ -21,6 +21,10 @@ class Rates(object):
|
|
|
21
21
|
flexibility in retrieving data either by specifying a starting position
|
|
22
22
|
and count of bars or by providing a specific date range.
|
|
23
23
|
|
|
24
|
+
Notes:
|
|
25
|
+
The `get_open, get_high, get_low, get_close, get_adj_close, get_returns,
|
|
26
|
+
get_volume` properties return data in Broker's timezone.
|
|
27
|
+
|
|
24
28
|
Example:
|
|
25
29
|
>>> rates = Rates("EURUSD", "1h")
|
|
26
30
|
>>> df = rates.get_historical_data(
|
|
@@ -62,8 +66,14 @@ class Rates(object):
|
|
|
62
66
|
self.start_pos = self._get_start_pos(start_pos, time_frame)
|
|
63
67
|
self.count = count
|
|
64
68
|
self._mt5_initialized()
|
|
65
|
-
self.
|
|
69
|
+
self.__data = self.get_rates_from_pos()
|
|
70
|
+
|
|
66
71
|
|
|
72
|
+
def _mt5_initialized(self):
|
|
73
|
+
"""Ensures the MetaTrader 5 Terminal is initialized."""
|
|
74
|
+
if not Mt5.initialize():
|
|
75
|
+
raise_mt5_error(message=INIT_MSG)
|
|
76
|
+
|
|
67
77
|
def _get_start_pos(self, index, time_frame):
|
|
68
78
|
if isinstance(index, int):
|
|
69
79
|
start_pos = index
|
|
@@ -112,11 +122,6 @@ class Rates(object):
|
|
|
112
122
|
)
|
|
113
123
|
return TIMEFRAMES[time_frame]
|
|
114
124
|
|
|
115
|
-
def _mt5_initialized(self):
|
|
116
|
-
"""Ensures the MetaTrader 5 Terminal is initialized."""
|
|
117
|
-
if not Mt5.initialize():
|
|
118
|
-
raise_mt5_error(message=INIT_MSG)
|
|
119
|
-
|
|
120
125
|
def _fetch_data(
|
|
121
126
|
self, start: Union[int, datetime],
|
|
122
127
|
count: Union[int, datetime]
|
|
@@ -160,6 +165,13 @@ class Rates(object):
|
|
|
160
165
|
Returns:
|
|
161
166
|
Union[pd.DataFrame, None]: A DataFrame containing historical
|
|
162
167
|
data if successful, otherwise None.
|
|
168
|
+
|
|
169
|
+
Raises:
|
|
170
|
+
ValueError: If `start_pos` or `count` is not provided during
|
|
171
|
+
initialization.
|
|
172
|
+
|
|
173
|
+
Notes:
|
|
174
|
+
The Datetime for this method is in Broker's timezone.
|
|
163
175
|
"""
|
|
164
176
|
if self.start_pos is None or self.count is None:
|
|
165
177
|
raise ValueError(
|
|
@@ -171,23 +183,23 @@ class Rates(object):
|
|
|
171
183
|
|
|
172
184
|
@property
|
|
173
185
|
def get_open(self):
|
|
174
|
-
return self.
|
|
186
|
+
return self.__data['Open']
|
|
175
187
|
|
|
176
188
|
@property
|
|
177
189
|
def get_high(self):
|
|
178
|
-
return self.
|
|
190
|
+
return self.__data['High']
|
|
179
191
|
|
|
180
192
|
@property
|
|
181
193
|
def get_low(self):
|
|
182
|
-
return self.
|
|
194
|
+
return self.__data['Low']
|
|
183
195
|
|
|
184
196
|
@property
|
|
185
197
|
def get_close(self):
|
|
186
|
-
return self.
|
|
198
|
+
return self.__data['Close']
|
|
187
199
|
|
|
188
200
|
@property
|
|
189
201
|
def get_adj_close(self):
|
|
190
|
-
return self.
|
|
202
|
+
return self.__data['Adj Close']
|
|
191
203
|
|
|
192
204
|
@property
|
|
193
205
|
def get_returns(self):
|
|
@@ -202,7 +214,7 @@ class Rates(object):
|
|
|
202
214
|
It calculates fractional change (also known as `per unit change or relative change`)
|
|
203
215
|
and `not percentage change`. If you need the percentage change, multiply these values by 100.
|
|
204
216
|
"""
|
|
205
|
-
data = self.
|
|
217
|
+
data = self.__data.copy()
|
|
206
218
|
data['Returns'] = data['Adj Close'].pct_change()
|
|
207
219
|
data = data.dropna()
|
|
208
220
|
return data['Returns']
|
|
@@ -230,6 +242,12 @@ class Rates(object):
|
|
|
230
242
|
Returns:
|
|
231
243
|
Union[pd.DataFrame, None]: A DataFrame containing historical data
|
|
232
244
|
if successful, otherwise None.
|
|
245
|
+
|
|
246
|
+
Raises:
|
|
247
|
+
ValueError: If the starting date is greater than the ending date.
|
|
248
|
+
|
|
249
|
+
Notes:
|
|
250
|
+
The Datetime for this method is in UTC timezone.
|
|
233
251
|
"""
|
|
234
252
|
df = self._fetch_data(date_from, date_to)
|
|
235
253
|
if save_csv and df is not None:
|
bbstrader/metatrader/trade.py
CHANGED
|
@@ -14,7 +14,7 @@ from bbstrader.metatrader.utils import (
|
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
# Configure the logger
|
|
17
|
-
logger = config_logger('trade.log', console_log=
|
|
17
|
+
logger = config_logger('trade.log', console_log=False)
|
|
18
18
|
|
|
19
19
|
class Trade(RiskManagement):
|
|
20
20
|
"""
|
|
@@ -160,7 +160,7 @@ class Trade(RiskManagement):
|
|
|
160
160
|
print()
|
|
161
161
|
self.risk_managment()
|
|
162
162
|
print(
|
|
163
|
-
f">>> Everything is OK, @{self.expert_name} is Running
|
|
163
|
+
f">>> Everything is OK, @{self.expert_name} is Running ...>>>\n")
|
|
164
164
|
|
|
165
165
|
def initialize(self):
|
|
166
166
|
"""
|
|
@@ -416,7 +416,7 @@ class Trade(RiskManagement):
|
|
|
416
416
|
request["action"] = Mt5.TRADE_ACTION_PENDING
|
|
417
417
|
request["type"] = self._order_type()[action][0]
|
|
418
418
|
|
|
419
|
-
self.break_even(
|
|
419
|
+
self.break_even(mm=mm)
|
|
420
420
|
if self.check(comment):
|
|
421
421
|
self.request_result(_price, request, action),
|
|
422
422
|
|
|
@@ -767,7 +767,7 @@ class Trade(RiskManagement):
|
|
|
767
767
|
return True
|
|
768
768
|
return False
|
|
769
769
|
|
|
770
|
-
def break_even(self, id: Optional[int] = None):
|
|
770
|
+
def break_even(self, mm=True, id: Optional[int] = None):
|
|
771
771
|
"""
|
|
772
772
|
Checks if it's time to put the break even,
|
|
773
773
|
if so , it will sets the break even ,and if the break even was already set,
|
|
@@ -776,8 +776,11 @@ class Trade(RiskManagement):
|
|
|
776
776
|
|
|
777
777
|
Args:
|
|
778
778
|
id (int): The strategy Id or Expert Id
|
|
779
|
+
mm (bool): Weither to manage the position or not
|
|
779
780
|
"""
|
|
780
781
|
time.sleep(0.1)
|
|
782
|
+
if not mm:
|
|
783
|
+
return
|
|
781
784
|
Id = id if id is not None else self.expert_id
|
|
782
785
|
positions = self.get_positions(symbol=self.symbol)
|
|
783
786
|
be = self.get_break_even()
|
|
@@ -1111,13 +1114,13 @@ class Trade(RiskManagement):
|
|
|
1111
1114
|
|
|
1112
1115
|
if len(tickets) == 0:
|
|
1113
1116
|
logger.info(
|
|
1114
|
-
f"ALL {
|
|
1117
|
+
f"ALL {pos_type.upper()} Positions closed, SYMBOL={self.symbol}.")
|
|
1115
1118
|
else:
|
|
1116
1119
|
logger.info(
|
|
1117
|
-
f"{len(tickets)} {
|
|
1120
|
+
f"{len(tickets)} {pos_type.upper()} Positions not closed, SYMBOL={self.symbol}")
|
|
1118
1121
|
else:
|
|
1119
1122
|
logger.info(
|
|
1120
|
-
f"No {
|
|
1123
|
+
f"No {pos_type.upper()} Positions to close, SYMBOL={self.symbol}.")
|
|
1121
1124
|
|
|
1122
1125
|
def get_stats(self) -> Tuple[Dict[str, Any]]:
|
|
1123
1126
|
"""
|
bbstrader/metatrader/utils.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from datetime import datetime
|
|
1
2
|
import MetaTrader5 as MT5
|
|
2
3
|
import logging
|
|
3
4
|
from typing import List, NamedTuple, Optional
|
|
@@ -216,7 +217,7 @@ class SymbolInfo(NamedTuple):
|
|
|
216
217
|
volume: int
|
|
217
218
|
volumehigh: int
|
|
218
219
|
volumelow: int
|
|
219
|
-
time:
|
|
220
|
+
time: datetime
|
|
220
221
|
digits: int
|
|
221
222
|
spread: int
|
|
222
223
|
spread_float: bool
|
|
@@ -316,7 +317,7 @@ class TickInfo(NamedTuple):
|
|
|
316
317
|
* flags: Tick flags
|
|
317
318
|
* volume_real: Volume for the current Last price with greater accuracy
|
|
318
319
|
"""
|
|
319
|
-
time:
|
|
320
|
+
time: datetime
|
|
320
321
|
bid: float
|
|
321
322
|
ask: float
|
|
322
323
|
last: float
|
bbstrader/trading/execution.py
CHANGED
|
@@ -165,10 +165,13 @@ def sma_trading(
|
|
|
165
165
|
time.sleep((60 * iter_time) - 1.5)
|
|
166
166
|
if iter_time == 1:
|
|
167
167
|
time_intervals += 1
|
|
168
|
-
elif iter_time ==
|
|
169
|
-
time_intervals +=
|
|
168
|
+
elif trade_time % iter_time == 0:
|
|
169
|
+
time_intervals += iter_time
|
|
170
170
|
else:
|
|
171
|
-
|
|
171
|
+
raise ValueError(
|
|
172
|
+
f"iter_time must be a multiple of the {tf} !!!"
|
|
173
|
+
f"(e.g; if time_frame is 15m, iter_time must be 1.5, 3, 3, 15 etc)"
|
|
174
|
+
)
|
|
172
175
|
if period.lower() == 'month':
|
|
173
176
|
if trade.days_end() and today != 'Friday':
|
|
174
177
|
sleep_time = trade.sleep_time()
|
|
@@ -484,10 +487,13 @@ def pair_trading(
|
|
|
484
487
|
|
|
485
488
|
if iter_time == 1:
|
|
486
489
|
time_intervals += 1
|
|
487
|
-
elif iter_time ==
|
|
488
|
-
time_intervals +=
|
|
490
|
+
elif trade_time % iter_time == 0:
|
|
491
|
+
time_intervals += iter_time
|
|
489
492
|
else:
|
|
490
|
-
|
|
493
|
+
raise ValueError(
|
|
494
|
+
f"iter_time must be a multiple of the {tf} !!!"
|
|
495
|
+
f"(e.g; if time_frame is 15m, iter_time must be 1.5, 3, 3, 15 etc)"
|
|
496
|
+
)
|
|
491
497
|
|
|
492
498
|
if period.lower() == 'month':
|
|
493
499
|
if p0.days_end() and today != 'Friday':
|
|
@@ -706,10 +712,13 @@ def ou_trading(
|
|
|
706
712
|
time.sleep((60 * iter_time) - 1.5)
|
|
707
713
|
if iter_time == 1:
|
|
708
714
|
time_intervals += 1
|
|
709
|
-
elif iter_time ==
|
|
710
|
-
time_intervals +=
|
|
715
|
+
elif trade_time % iter_time == 0:
|
|
716
|
+
time_intervals += iter_time
|
|
711
717
|
else:
|
|
712
|
-
|
|
718
|
+
raise ValueError(
|
|
719
|
+
f"iter_time must be a multiple of the {tf} !!!"
|
|
720
|
+
f"(e.g; if time_frame is 15m, iter_time must be 1.5, 3, 3, 15 etc)"
|
|
721
|
+
)
|
|
713
722
|
|
|
714
723
|
if period.lower() == 'month':
|
|
715
724
|
if trade.days_end() and today != 'Friday':
|
|
@@ -918,10 +927,13 @@ def arch_trading(
|
|
|
918
927
|
time.sleep((60 * iter_time) - 1.5)
|
|
919
928
|
if iter_time == 1:
|
|
920
929
|
time_intervals += 1
|
|
921
|
-
elif iter_time ==
|
|
922
|
-
time_intervals +=
|
|
930
|
+
elif trade_time % iter_time == 0:
|
|
931
|
+
time_intervals += iter_time
|
|
923
932
|
else:
|
|
924
|
-
|
|
933
|
+
raise ValueError(
|
|
934
|
+
f"iter_time must be a multiple of the {tf} !!!"
|
|
935
|
+
f"(e.g; if time_frame is 15m, iter_time must be 1.5, 3, 3, 15 etc)"
|
|
936
|
+
)
|
|
925
937
|
|
|
926
938
|
if period.lower() == 'month':
|
|
927
939
|
if trade.days_end() and today != 'Friday':
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
bbstrader/__ini__.py,sha256=pXy9hM6Yh9hvIHRQS56TzEfYj97YYoc48oiYuYOfns4,478
|
|
2
|
+
bbstrader/strategies.py,sha256=6USRp43fsLLe2rT608Glz6lmea6bvjKx8fQEgOWyUGI,24510
|
|
3
|
+
bbstrader/tseries.py,sha256=M9x5jcdvIiAAAv1V2PSldguOHT4K6tmR2EYW_IswqI0,21779
|
|
4
|
+
bbstrader/btengine/__init__.py,sha256=oGyNWUAqzpounayQ5ptww6vFUp58J-af-ooCMf9hFV0,3156
|
|
5
|
+
bbstrader/btengine/backtest.py,sha256=eqeoNfm2_d0gEvSoXTqbNnEkLCq76UQEQqslL31iwSI,36744
|
|
6
|
+
bbstrader/btengine/data.py,sha256=q8DQpdknbzLfFKIso5sRyKw8w8clH-uDxs_UqLKTT2g,13933
|
|
7
|
+
bbstrader/btengine/event.py,sha256=quqNzvfvqtGYGVg9id3uNHb3EhzH5FCWYdeCn2KZ9sc,7894
|
|
8
|
+
bbstrader/btengine/execution.py,sha256=g5p_7XXU7fgxkzoXNd5SiHITUWcURpd9ViYumtlxF0g,2646
|
|
9
|
+
bbstrader/btengine/performance.py,sha256=Pz-qZb7EglPt8TMKs5ZCgo-af54UCOfqWKpEH8B19rQ,10211
|
|
10
|
+
bbstrader/btengine/portfolio.py,sha256=RXGJTmg1NIq0MSkMB6v6hmCG4xfdwLo9rO1_UCAX7As,14008
|
|
11
|
+
bbstrader/btengine/strategy.py,sha256=G9_vcAzH-oT3vk1t3espXP-snrN2uXTEZh3sVCyFzWM,1554
|
|
12
|
+
bbstrader/metatrader/__init__.py,sha256=y4JLz05esm3PKerHMgtd3dmRpa7yUvWVuj_xOnlhXSA,261
|
|
13
|
+
bbstrader/metatrader/account.py,sha256=qbkcPbIbuld-ZVrNY8zW8cTSpPPdKMw9zKk5HQD108g,44301
|
|
14
|
+
bbstrader/metatrader/rates.py,sha256=Ro4NIAjR_cjMivrfvixsEtivNAx0ACvPoBosYTCuzZg,9383
|
|
15
|
+
bbstrader/metatrader/risk.py,sha256=qMDLqrwD8foKOW8jCnhwt0Lvxgtl0uwKYgRqhSbNeh8,25827
|
|
16
|
+
bbstrader/metatrader/trade.py,sha256=Y0WPJC2rVETx5wmZUpRzVRj42gQhkh-8LNcOBYlpzdg,57390
|
|
17
|
+
bbstrader/metatrader/utils.py,sha256=UaxsQ2myvpPGSvO_Xs3T9cuT9rwGRUhDE2YyQA4u05I,18963
|
|
18
|
+
bbstrader/models/__init__.py,sha256=6tAj9V9vgwesgPVMKznwRB3k8-Ec8Q73Di5p2UO0qlA,274
|
|
19
|
+
bbstrader/models/risk.py,sha256=2fFBqsY2v8Kd6oU8t8h2h-Sp8joVqetA-t21rjkT9U4,13593
|
|
20
|
+
bbstrader/trading/__init__.py,sha256=yZ85EALV2sSCzCPxaeFYlk1JJhYQq2C-xSd5EEQYvI8,82
|
|
21
|
+
bbstrader/trading/execution.py,sha256=Ru1TiVrxCVr9YOXpweb1KiqHMANeTsKqfsth8Ho-nbg,47288
|
|
22
|
+
bbstrader/trading/run.py,sha256=UA5Sn5nWOqsezZVGCM_kjOPPsu_IxMdSABUBnBAJA-k,3474
|
|
23
|
+
bbstrader/trading/utils.py,sha256=Eu_cBnfPcOGel4Lj6Dc-UCl-h7NqR8Rfv9RZtaxNRos,7711
|
|
24
|
+
bbstrader-0.1.6.dist-info/LICENSE,sha256=1EudjwwP2oTJy8Vh0e-Kzv8VZZU95y-t6c3DYhR51uc,1115
|
|
25
|
+
bbstrader-0.1.6.dist-info/METADATA,sha256=an7eJE6u3flDzS0irxAmooZX5IEf2t8l12GnnT7rGE0,9218
|
|
26
|
+
bbstrader-0.1.6.dist-info/WHEEL,sha256=uCRv0ZEik_232NlR4YDw4Pv3Ajt5bKvMH13NUU7hFuI,91
|
|
27
|
+
bbstrader-0.1.6.dist-info/top_level.txt,sha256=Wwj322jZmxGZ6gD_TdaPiPLjED5ReObm5omerwlmZIg,10
|
|
28
|
+
bbstrader-0.1.6.dist-info/RECORD,,
|
bbstrader-0.1.5.dist-info/RECORD
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
bbstrader/__ini__.py,sha256=pXy9hM6Yh9hvIHRQS56TzEfYj97YYoc48oiYuYOfns4,478
|
|
2
|
-
bbstrader/strategies.py,sha256=6USRp43fsLLe2rT608Glz6lmea6bvjKx8fQEgOWyUGI,24510
|
|
3
|
-
bbstrader/tseries.py,sha256=M9x5jcdvIiAAAv1V2PSldguOHT4K6tmR2EYW_IswqI0,21779
|
|
4
|
-
bbstrader/btengine/__init__.py,sha256=oGyNWUAqzpounayQ5ptww6vFUp58J-af-ooCMf9hFV0,3156
|
|
5
|
-
bbstrader/btengine/backtest.py,sha256=eXKTIQxPWFN3RdTXWQTE2ybc4YI0svoWobN6Cz2xR14,36656
|
|
6
|
-
bbstrader/btengine/data.py,sha256=-8k3tBf-sHnV7GU26xxaGusK_SYxm6TuIvCTMcR_zY4,13810
|
|
7
|
-
bbstrader/btengine/event.py,sha256=k27f8pMnF8iCiLT748Zcpc_nUnfL5QbxkGvefIdEqPA,7820
|
|
8
|
-
bbstrader/btengine/execution.py,sha256=0U4ukV8a5G1eJTvyXHxkdT6E5Jk2UoDUIok0SGdRfWk,2636
|
|
9
|
-
bbstrader/btengine/performance.py,sha256=Pz-qZb7EglPt8TMKs5ZCgo-af54UCOfqWKpEH8B19rQ,10211
|
|
10
|
-
bbstrader/btengine/portfolio.py,sha256=RXGJTmg1NIq0MSkMB6v6hmCG4xfdwLo9rO1_UCAX7As,14008
|
|
11
|
-
bbstrader/btengine/strategy.py,sha256=tY5ek37NxLrYftgzJ4CqMGDFv5oMkvMsBbOkkOGghKw,1384
|
|
12
|
-
bbstrader/metatrader/__init__.py,sha256=y4JLz05esm3PKerHMgtd3dmRpa7yUvWVuj_xOnlhXSA,261
|
|
13
|
-
bbstrader/metatrader/account.py,sha256=g3fRzwxy473rEVRuWyJ70NzoeWkbhwph0d2yW-AapPU,43748
|
|
14
|
-
bbstrader/metatrader/rates.py,sha256=PH5Iz46YTfVuguVWDvRl0rVmEggeFsUXfbO2GgGScqU,8787
|
|
15
|
-
bbstrader/metatrader/risk.py,sha256=qMDLqrwD8foKOW8jCnhwt0Lvxgtl0uwKYgRqhSbNeh8,25827
|
|
16
|
-
bbstrader/metatrader/trade.py,sha256=sBFUMwP9OLKFCTJH8jD_s143O1R9pVKCEL3a76l_UPs,57296
|
|
17
|
-
bbstrader/metatrader/utils.py,sha256=Tw98T4iBqlMtm9jVnwsf9mjKxZkD_rA0u8xJLqoHl0Q,18922
|
|
18
|
-
bbstrader/models/__init__.py,sha256=6tAj9V9vgwesgPVMKznwRB3k8-Ec8Q73Di5p2UO0qlA,274
|
|
19
|
-
bbstrader/models/risk.py,sha256=2fFBqsY2v8Kd6oU8t8h2h-Sp8joVqetA-t21rjkT9U4,13593
|
|
20
|
-
bbstrader/trading/__init__.py,sha256=yZ85EALV2sSCzCPxaeFYlk1JJhYQq2C-xSd5EEQYvI8,82
|
|
21
|
-
bbstrader/trading/execution.py,sha256=geiIiR9ldTJvM6rapa66Xug-gRcA_YqfA6kCr54lnRw,46708
|
|
22
|
-
bbstrader/trading/run.py,sha256=UA5Sn5nWOqsezZVGCM_kjOPPsu_IxMdSABUBnBAJA-k,3474
|
|
23
|
-
bbstrader/trading/utils.py,sha256=Eu_cBnfPcOGel4Lj6Dc-UCl-h7NqR8Rfv9RZtaxNRos,7711
|
|
24
|
-
bbstrader-0.1.5.dist-info/LICENSE,sha256=1EudjwwP2oTJy8Vh0e-Kzv8VZZU95y-t6c3DYhR51uc,1115
|
|
25
|
-
bbstrader-0.1.5.dist-info/METADATA,sha256=oBK1Mvt0N3Ha7x3E76r58n_en1BRay4PqPLJixxdHXI,9218
|
|
26
|
-
bbstrader-0.1.5.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
|
|
27
|
-
bbstrader-0.1.5.dist-info/top_level.txt,sha256=Wwj322jZmxGZ6gD_TdaPiPLjED5ReObm5omerwlmZIg,10
|
|
28
|
-
bbstrader-0.1.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|