PyAlgoEngine 0.4.1__tar.gz → 0.4.2__tar.gz
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.
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/PKG-INFO +1 -1
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/PyAlgoEngine.egg-info/PKG-INFO +1 -1
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/__init__.py +1 -1
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/back_test/sim_match.py +1 -1
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/base/market_utils.py +3 -3
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/base/trade_utils.py +6 -6
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/engine/algo_engine.py +2 -2
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/engine/market_engine.py +4 -7
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/profile/__init__.py +12 -5
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/profile/cn.py +18 -23
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/LICENSE +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/PyAlgoEngine.egg-info/SOURCES.txt +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/PyAlgoEngine.egg-info/dependency_links.txt +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/PyAlgoEngine.egg-info/requires.txt +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/PyAlgoEngine.egg-info/top_level.txt +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/README.md +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/back_test/__init__.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/back_test/__main__.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/back_test/replay.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/base/__init__.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/base/console_utils.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/base/finance_decimal.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/base/technical_analysis.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/base/telemetrics.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/engine/__init__.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/engine/event_engine.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/engine/trade_engine.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/monitor/__init__.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/monitor/advanced_data_interface.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/strategy/__init__.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/algo_engine/strategy/strategy_engine.py +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/setup.cfg +0 -0
- {PyAlgoEngine-0.4.1 → PyAlgoEngine-0.4.2}/setup.py +0 -0
|
@@ -269,7 +269,7 @@ class MarketData(dict, metaclass=abc.ABCMeta):
|
|
|
269
269
|
|
|
270
270
|
@property
|
|
271
271
|
def market_time(self) -> datetime.datetime | datetime.date:
|
|
272
|
-
return datetime.datetime.fromtimestamp(self.timestamp, tz=PROFILE.
|
|
272
|
+
return datetime.datetime.fromtimestamp(self.timestamp, tz=PROFILE.time_zone)
|
|
273
273
|
|
|
274
274
|
@property
|
|
275
275
|
@abc.abstractmethod
|
|
@@ -823,9 +823,9 @@ class BarData(MarketData):
|
|
|
823
823
|
@property
|
|
824
824
|
def bar_start_time(self) -> datetime.datetime:
|
|
825
825
|
if 'start_timestamp' in self:
|
|
826
|
-
return datetime.datetime.fromtimestamp(self['start_timestamp'], tz=PROFILE.
|
|
826
|
+
return datetime.datetime.fromtimestamp(self['start_timestamp'], tz=PROFILE.time_zone)
|
|
827
827
|
else:
|
|
828
|
-
return datetime.datetime.fromtimestamp(self['timestamp'] - self['bar_span'], tz=PROFILE.
|
|
828
|
+
return datetime.datetime.fromtimestamp(self['timestamp'] - self['bar_span'], tz=PROFILE.time_zone)
|
|
829
829
|
|
|
830
830
|
@property
|
|
831
831
|
def vwap(self) -> float:
|
|
@@ -152,7 +152,7 @@ class TradeBaseClass(dict, metaclass=abc.ABCMeta):
|
|
|
152
152
|
|
|
153
153
|
@property
|
|
154
154
|
def market_time(self) -> datetime.datetime | datetime.date:
|
|
155
|
-
return datetime.datetime.fromtimestamp(self.timestamp, tz=PROFILE.
|
|
155
|
+
return datetime.datetime.fromtimestamp(self.timestamp, tz=PROFILE.time_zone)
|
|
156
156
|
|
|
157
157
|
|
|
158
158
|
class TradeReport(TradeBaseClass):
|
|
@@ -377,7 +377,7 @@ class TradeReport(TradeBaseClass):
|
|
|
377
377
|
|
|
378
378
|
@property
|
|
379
379
|
def trade_time(self) -> datetime.datetime:
|
|
380
|
-
return datetime.datetime.fromtimestamp(self.timestamp, tz=PROFILE.
|
|
380
|
+
return datetime.datetime.fromtimestamp(self.timestamp, tz=PROFILE.time_zone)
|
|
381
381
|
|
|
382
382
|
|
|
383
383
|
class TradeInstruction(TradeBaseClass):
|
|
@@ -681,26 +681,26 @@ class TradeInstruction(TradeBaseClass):
|
|
|
681
681
|
|
|
682
682
|
@property
|
|
683
683
|
def start_time(self) -> datetime.datetime | None:
|
|
684
|
-
return datetime.datetime.fromtimestamp(self.timestamp, tz=PROFILE.
|
|
684
|
+
return datetime.datetime.fromtimestamp(self.timestamp, tz=PROFILE.time_zone)
|
|
685
685
|
|
|
686
686
|
@property
|
|
687
687
|
def placed_time(self) -> datetime.datetime | None:
|
|
688
688
|
if 'ts_placed' in self:
|
|
689
|
-
return datetime.datetime.fromtimestamp(self['ts_placed'], tz=PROFILE.
|
|
689
|
+
return datetime.datetime.fromtimestamp(self['ts_placed'], tz=PROFILE.time_zone)
|
|
690
690
|
|
|
691
691
|
return None
|
|
692
692
|
|
|
693
693
|
@property
|
|
694
694
|
def canceled_time(self) -> datetime.datetime | None:
|
|
695
695
|
if 'ts_canceled' in self:
|
|
696
|
-
return datetime.datetime.fromtimestamp(self['ts_canceled'], tz=PROFILE.
|
|
696
|
+
return datetime.datetime.fromtimestamp(self['ts_canceled'], tz=PROFILE.time_zone)
|
|
697
697
|
|
|
698
698
|
return None
|
|
699
699
|
|
|
700
700
|
@property
|
|
701
701
|
def finished_time(self) -> datetime.datetime | None:
|
|
702
702
|
if 'ts_finished' in self:
|
|
703
|
-
return datetime.datetime.fromtimestamp(self['ts_finished'], tz=PROFILE.
|
|
703
|
+
return datetime.datetime.fromtimestamp(self['ts_finished'], tz=PROFILE.time_zone)
|
|
704
704
|
|
|
705
705
|
return None
|
|
706
706
|
|
|
@@ -453,14 +453,14 @@ class AlgoTemplate(object, metaclass=abc.ABCMeta):
|
|
|
453
453
|
if self.ts_started is None:
|
|
454
454
|
return None
|
|
455
455
|
|
|
456
|
-
return datetime.datetime.fromtimestamp(self.ts_started, tz=self.algo_engine.mds.profile.
|
|
456
|
+
return datetime.datetime.fromtimestamp(self.ts_started, tz=self.algo_engine.mds.profile.time_zone)
|
|
457
457
|
|
|
458
458
|
@property
|
|
459
459
|
def finish_time(self) -> datetime.datetime | None:
|
|
460
460
|
if self.ts_finished is None:
|
|
461
461
|
return None
|
|
462
462
|
|
|
463
|
-
return datetime.datetime.fromtimestamp(self.ts_finished, tz=self.algo_engine.mds.profile.
|
|
463
|
+
return datetime.datetime.fromtimestamp(self.ts_finished, tz=self.algo_engine.mds.profile.time_zone)
|
|
464
464
|
|
|
465
465
|
|
|
466
466
|
class Passive(AlgoTemplate):
|
|
@@ -8,7 +8,7 @@ from typing import Self
|
|
|
8
8
|
|
|
9
9
|
from . import LOGGER
|
|
10
10
|
from ..base import TickData, TradeData, OrderBook, MarketData, TransactionSide
|
|
11
|
-
from ..profile import PROFILE, Profile
|
|
11
|
+
from ..profile import PROFILE, Profile
|
|
12
12
|
|
|
13
13
|
LOGGER = LOGGER.getChild('MarketEngine')
|
|
14
14
|
|
|
@@ -199,9 +199,6 @@ class MarketDataService(object):
|
|
|
199
199
|
self.monitor.pop(monitor_id)
|
|
200
200
|
self.monitor_manager.pop_monitor(monitor_id)
|
|
201
201
|
|
|
202
|
-
def init_cn_override(self):
|
|
203
|
-
self.profile = PROFILE_CN
|
|
204
|
-
|
|
205
202
|
def _on_trade_data(self, trade_data: TradeData):
|
|
206
203
|
ticker = trade_data.ticker
|
|
207
204
|
|
|
@@ -281,8 +278,8 @@ class MarketDataService(object):
|
|
|
281
278
|
def trade_time_between(self, start_time: datetime.datetime | float, end_time: datetime.datetime | float, **kwargs) -> datetime.timedelta:
|
|
282
279
|
return self.profile.trade_time_between(start_time=start_time, end_time=end_time, **kwargs)
|
|
283
280
|
|
|
284
|
-
def
|
|
285
|
-
return self.profile.
|
|
281
|
+
def is_market_session(self, market_time: datetime.datetime | float | int) -> bool:
|
|
282
|
+
return self.profile.is_market_session(timestamp=market_time)
|
|
286
283
|
|
|
287
284
|
def clear(self):
|
|
288
285
|
# self._market_price.clear()
|
|
@@ -310,7 +307,7 @@ class MarketDataService(object):
|
|
|
310
307
|
if self._timestamp is None:
|
|
311
308
|
return None
|
|
312
309
|
else:
|
|
313
|
-
return datetime.datetime.fromtimestamp(self._timestamp, tz=self.profile.
|
|
310
|
+
return datetime.datetime.fromtimestamp(self._timestamp, tz=self.profile.time_zone)
|
|
314
311
|
else:
|
|
315
312
|
return self._market_time
|
|
316
313
|
|
|
@@ -14,7 +14,7 @@ class Profile(object, metaclass=abc.ABCMeta):
|
|
|
14
14
|
self.session_end = session_end
|
|
15
15
|
self.session_break = [] if session_break is None else session_break
|
|
16
16
|
|
|
17
|
-
self.
|
|
17
|
+
self.time_zone = None
|
|
18
18
|
|
|
19
19
|
@abc.abstractmethod
|
|
20
20
|
def override_profile(self, profile: Self): ...
|
|
@@ -24,9 +24,16 @@ class Profile(object, metaclass=abc.ABCMeta):
|
|
|
24
24
|
...
|
|
25
25
|
|
|
26
26
|
@abc.abstractmethod
|
|
27
|
-
def
|
|
27
|
+
def is_market_session(self, timestamp: float | int | datetime.datetime) -> bool:
|
|
28
28
|
...
|
|
29
29
|
|
|
30
|
+
@property
|
|
31
|
+
def range_break(self) -> list[dict]:
|
|
32
|
+
"""
|
|
33
|
+
an range break designed for plotly.
|
|
34
|
+
"""
|
|
35
|
+
return []
|
|
36
|
+
|
|
30
37
|
|
|
31
38
|
class DefaultProfile(Profile):
|
|
32
39
|
def __init__(self):
|
|
@@ -41,10 +48,10 @@ class DefaultProfile(Profile):
|
|
|
41
48
|
|
|
42
49
|
def trade_time_between(self, start_time: datetime.datetime | float, end_time: datetime.datetime | float, **kwargs) -> datetime.timedelta:
|
|
43
50
|
if start_time is not None and isinstance(start_time, (float, int)):
|
|
44
|
-
start_time = datetime.datetime.fromtimestamp(start_time, tz=self.
|
|
51
|
+
start_time = datetime.datetime.fromtimestamp(start_time, tz=self.time_zone)
|
|
45
52
|
|
|
46
53
|
if end_time is not None and isinstance(end_time, (float, int)):
|
|
47
|
-
end_time = datetime.datetime.fromtimestamp(end_time, tz=self.
|
|
54
|
+
end_time = datetime.datetime.fromtimestamp(end_time, tz=self.time_zone)
|
|
48
55
|
|
|
49
56
|
if start_time is None or end_time is None:
|
|
50
57
|
return datetime.timedelta(seconds=0)
|
|
@@ -54,7 +61,7 @@ class DefaultProfile(Profile):
|
|
|
54
61
|
|
|
55
62
|
return end_time - start_time
|
|
56
63
|
|
|
57
|
-
def
|
|
64
|
+
def is_market_session(self, timestamp: float | int | datetime.datetime) -> bool:
|
|
58
65
|
return True
|
|
59
66
|
|
|
60
67
|
|
|
@@ -31,7 +31,7 @@ class ProfileCN(Profile):
|
|
|
31
31
|
profile.in_trade_session = self.in_trade_session
|
|
32
32
|
|
|
33
33
|
@functools.lru_cache
|
|
34
|
-
def
|
|
34
|
+
def query_trade_calendar(self, start_date: datetime.date, end_date: datetime.date, market='XSHG', tz='UTC') -> list[datetime.date]:
|
|
35
35
|
import pandas as pd
|
|
36
36
|
|
|
37
37
|
if market in self.trade_calendar:
|
|
@@ -72,7 +72,7 @@ class ProfileCN(Profile):
|
|
|
72
72
|
if start_date == end_date:
|
|
73
73
|
offset = 0
|
|
74
74
|
else:
|
|
75
|
-
market_date_list = self.
|
|
75
|
+
market_date_list = self.query_trade_calendar(start_date=start_date, end_date=end_date, **kwargs)
|
|
76
76
|
if not market_date_list:
|
|
77
77
|
offset = 0
|
|
78
78
|
else:
|
|
@@ -106,11 +106,11 @@ class ProfileCN(Profile):
|
|
|
106
106
|
implied_date = datetime.date.today()
|
|
107
107
|
|
|
108
108
|
if isinstance(start_time, (float, int)):
|
|
109
|
-
start_time = datetime.datetime.fromtimestamp(start_time, tz=self.
|
|
109
|
+
start_time = datetime.datetime.fromtimestamp(start_time, tz=self.time_zone)
|
|
110
110
|
implied_date = start_time.date()
|
|
111
111
|
|
|
112
112
|
if isinstance(end_time, (float, int)):
|
|
113
|
-
end_time = datetime.datetime.fromtimestamp(end_time, tz=self.
|
|
113
|
+
end_time = datetime.datetime.fromtimestamp(end_time, tz=self.time_zone)
|
|
114
114
|
implied_date = end_time.date()
|
|
115
115
|
|
|
116
116
|
if isinstance(start_time, datetime.time):
|
|
@@ -164,29 +164,24 @@ class ProfileCN(Profile):
|
|
|
164
164
|
else:
|
|
165
165
|
raise NotImplementedError(f'Invalid fmt {fmt}, should be "timestamp" or "timedelta"')
|
|
166
166
|
|
|
167
|
-
def
|
|
168
|
-
if
|
|
169
|
-
market_time = datetime.datetime.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
market_date = market_time.date()
|
|
175
|
-
market_time = market_time.time()
|
|
176
|
-
|
|
177
|
-
if not self.is_trade_day(market_date=market_date):
|
|
178
|
-
return False
|
|
179
|
-
|
|
180
|
-
if market_time < datetime.time(9, 30):
|
|
181
|
-
return False
|
|
182
|
-
|
|
183
|
-
if datetime.time(11, 30) < market_time < datetime.time(13, 00):
|
|
184
|
-
return False
|
|
167
|
+
def is_market_session(self, timestamp: float | int | datetime.datetime) -> bool:
|
|
168
|
+
if isinstance(timestamp, (float, int)):
|
|
169
|
+
market_time = datetime.datetime.fromtimestamp(timestamp, tz=self.time_zone).time()
|
|
170
|
+
elif isinstance(timestamp, datetime.datetime):
|
|
171
|
+
market_time = timestamp
|
|
172
|
+
else:
|
|
173
|
+
raise TypeError(f'Expect timestamp to be a float, int or datetime, got {type(timestamp)}!')
|
|
185
174
|
|
|
186
|
-
if market_time
|
|
175
|
+
if (market_time < datetime.time(9, 30)
|
|
176
|
+
or datetime.time(11, 30) < market_time < datetime.time(13, 0)
|
|
177
|
+
or datetime.time(15, 0) < market_time):
|
|
187
178
|
return False
|
|
188
179
|
|
|
189
180
|
return True
|
|
190
181
|
|
|
182
|
+
@property
|
|
183
|
+
def range_break(self) -> list[dict]:
|
|
184
|
+
return [dict(bounds=[0, 9.5], pattern="hour"), dict(bounds=[11.5, 13], pattern="hour"), dict(bounds=[15, 24], pattern="hour")]
|
|
185
|
+
|
|
191
186
|
|
|
192
187
|
PROFILE_CN = ProfileCN()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|