PyAlgoEngine 0.5.4.post7__tar.gz → 0.5.4.post10__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.5.4.post7 → pyalgoengine-0.5.4.post10}/PKG-INFO +1 -1
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/PyAlgoEngine.egg-info/PKG-INFO +1 -1
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/__init__.py +1 -1
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/base/market_utils.py +89 -8
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/profile/__init__.py +3 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/utils/data_utils.py +4 -3
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/LICENSE +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/PyAlgoEngine.egg-info/SOURCES.txt +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/PyAlgoEngine.egg-info/dependency_links.txt +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/PyAlgoEngine.egg-info/requires.txt +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/PyAlgoEngine.egg-info/top_level.txt +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/README.md +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/apps/__init__.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/apps/backtest/__init__.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/apps/backtest/doc_server.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/apps/backtest/tester.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/apps/backtest/web_app.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/apps/bokeh_server.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/apps/demo/__init__.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/apps/demo/test.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/backtest/__init__.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/backtest/__main__.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/backtest/metrics.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/backtest/replay.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/backtest/sim_match.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/base/__init__.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/base/console_utils.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/base/finance_decimal.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/base/technical_analysis.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/base/telemetrics.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/base/trade_utils.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/engine/__init__.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/engine/algo_engine.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/engine/event_engine.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/engine/market_engine.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/engine/trade_engine.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/monitor/__init__.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/monitor/advanced_data_interface.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/profile/cn.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/strategy/__init__.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/strategy/strategy_engine.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/utils/__init__.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/utils/commit_regularizer.py +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/setup.cfg +0 -0
- {pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/setup.py +0 -0
|
@@ -11,6 +11,7 @@ from ctypes import c_ulong, c_double, c_wchar, c_int, c_longlong
|
|
|
11
11
|
from multiprocessing import RawValue, RawArray
|
|
12
12
|
from typing import overload, Literal
|
|
13
13
|
|
|
14
|
+
import ciso8601
|
|
14
15
|
import numpy as np
|
|
15
16
|
|
|
16
17
|
from . import LOGGER, PROFILE
|
|
@@ -475,6 +476,22 @@ class OrderBook(MarketData):
|
|
|
475
476
|
return [entry[1] for entry in self._book]
|
|
476
477
|
|
|
477
478
|
def __init__(self, *, ticker: str, timestamp: float, bid: list[list[float | int]] = None, ask: list[list[float | int]] = None, **kwargs):
|
|
479
|
+
"""
|
|
480
|
+
Initialize an OrderBook instance with market data.
|
|
481
|
+
|
|
482
|
+
Args:
|
|
483
|
+
ticker (str): The ticker symbol of the financial instrument.
|
|
484
|
+
timestamp (float): The timestamp of the market data.
|
|
485
|
+
bid (list[list[float | int]], optional): A list of bid data, where each sublist contains price, volume, and optionally, order details. Defaults to None.
|
|
486
|
+
ask (list[list[float | int]], optional): A list of ask data.
|
|
487
|
+
**kwargs: Additional key-value pairs for parsing extra data fields.
|
|
488
|
+
|
|
489
|
+
Attributes:
|
|
490
|
+
bid (OrderBook.Book): An instance of the Book class representing the bid side of the order book.
|
|
491
|
+
ask (OrderBook.Book): An instance of the Book class representing the ask side of the order book.
|
|
492
|
+
|
|
493
|
+
The `OrderBook` class extends `MarketData` and represents an order book with bids and asks. The `__init__` method initializes the order book with the provided bid and ask data and parses any additional keyword arguments to populate other attributes.
|
|
494
|
+
"""
|
|
478
495
|
super().__init__(ticker=ticker, timestamp=timestamp)
|
|
479
496
|
self.update(
|
|
480
497
|
bid=[] if bid is None else bid,
|
|
@@ -889,7 +906,7 @@ class DailyBar(BarData):
|
|
|
889
906
|
def __init__(
|
|
890
907
|
self, *,
|
|
891
908
|
ticker: str,
|
|
892
|
-
market_date: datetime.date, # The market date of the bar, if with 1D data, or the END date of the bar.
|
|
909
|
+
market_date: datetime.date | str, # The market date of the bar, if with 1D data, or the END date of the bar.
|
|
893
910
|
timestamp: float = None,
|
|
894
911
|
start_date: datetime.date = None,
|
|
895
912
|
bar_span: datetime.timedelta | int = None, # expect to be a timedelta for several days, or the number of days
|
|
@@ -902,6 +919,9 @@ class DailyBar(BarData):
|
|
|
902
919
|
trade_count: int = 0,
|
|
903
920
|
**kwargs
|
|
904
921
|
):
|
|
922
|
+
if isinstance(market_date, str):
|
|
923
|
+
market_date = datetime.date.fromisoformat(market_date)
|
|
924
|
+
|
|
905
925
|
if bar_span is None and start_date is None:
|
|
906
926
|
raise ValueError('Must assign ether datetime.date or bar_span or both.')
|
|
907
927
|
elif start_date is None:
|
|
@@ -941,6 +961,54 @@ class DailyBar(BarData):
|
|
|
941
961
|
def __repr__(self):
|
|
942
962
|
return f'<{self.__class__.__name__}>([{self.market_time:%Y-%m-%d}] {self.ticker}, open={self.open_price}, close={self.close_price}, high={self.high_price}, low={self.low_price})'
|
|
943
963
|
|
|
964
|
+
def to_json(self, fmt='str', **kwargs) -> str | dict:
|
|
965
|
+
data_dict = super().to_json(fmt='dict', **kwargs)
|
|
966
|
+
|
|
967
|
+
data_dict['market_date'] = self.market_date.isoformat()
|
|
968
|
+
|
|
969
|
+
if fmt == 'dict':
|
|
970
|
+
return data_dict
|
|
971
|
+
elif fmt == 'str':
|
|
972
|
+
return json.dumps(data_dict, **kwargs)
|
|
973
|
+
else:
|
|
974
|
+
raise ValueError(f'Invalid format {fmt}, except "dict" or "str".')
|
|
975
|
+
|
|
976
|
+
def to_list(self) -> list[float | int | str | bool]:
|
|
977
|
+
return [self.__class__.__name__,
|
|
978
|
+
self.ticker,
|
|
979
|
+
self.market_date.isoformat(),
|
|
980
|
+
self.timestamp,
|
|
981
|
+
self.high_price,
|
|
982
|
+
self.low_price,
|
|
983
|
+
self.open_price,
|
|
984
|
+
self.close_price,
|
|
985
|
+
self['bar_span'],
|
|
986
|
+
self.volume,
|
|
987
|
+
self.notional,
|
|
988
|
+
self.trade_count]
|
|
989
|
+
|
|
990
|
+
@classmethod
|
|
991
|
+
def from_list(cls, data_list: list[float | int | str | bool]) -> BarData:
|
|
992
|
+
(dtype, ticker, market_date, timestamp, high_price, low_price, open_price, close_price,
|
|
993
|
+
bar_span, volume, notional, trade_count) = data_list
|
|
994
|
+
|
|
995
|
+
if dtype != cls.__name__:
|
|
996
|
+
raise TypeError(f'dtype mismatch, expect {cls.__name__}, got {dtype}.')
|
|
997
|
+
|
|
998
|
+
return cls(
|
|
999
|
+
ticker=ticker,
|
|
1000
|
+
market_date=market_date,
|
|
1001
|
+
timestamp=timestamp,
|
|
1002
|
+
high_price=high_price,
|
|
1003
|
+
low_price=low_price,
|
|
1004
|
+
open_price=open_price,
|
|
1005
|
+
close_price=close_price,
|
|
1006
|
+
bar_span=datetime.timedelta(bar_span) if bar_span else None,
|
|
1007
|
+
volume=volume,
|
|
1008
|
+
notional=notional,
|
|
1009
|
+
trade_count=trade_count
|
|
1010
|
+
)
|
|
1011
|
+
|
|
944
1012
|
@property
|
|
945
1013
|
def bar_span(self) -> datetime.timedelta:
|
|
946
1014
|
return datetime.timedelta(days=self['bar_span'])
|
|
@@ -982,6 +1050,8 @@ class TickData(MarketData):
|
|
|
982
1050
|
ask_price: float = None,
|
|
983
1051
|
ask_volume: float = None,
|
|
984
1052
|
order_book: OrderBook = None,
|
|
1053
|
+
bid: list[list[float | int]] = None,
|
|
1054
|
+
ask: list[list[float | int]] = None,
|
|
985
1055
|
total_traded_volume: float = 0.,
|
|
986
1056
|
total_traded_notional: float = 0.,
|
|
987
1057
|
total_trade_count: int = 0,
|
|
@@ -996,6 +1066,23 @@ class TickData(MarketData):
|
|
|
996
1066
|
total_trade_count=total_trade_count,
|
|
997
1067
|
)
|
|
998
1068
|
|
|
1069
|
+
if order_book is not None:
|
|
1070
|
+
self['order_book'] = {'bid': order_book['bid'], 'ask': order_book['ask']}
|
|
1071
|
+
elif bid and ask:
|
|
1072
|
+
self['order_book'] = {
|
|
1073
|
+
'bid': sorted(bid, key=lambda _: _[0], reverse=True),
|
|
1074
|
+
'ask': sorted(ask, key=lambda _: _[0], reverse=False)
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
if bid_price is None:
|
|
1078
|
+
bid_price, _, *_ = bid[0]
|
|
1079
|
+
if bid_volume is None:
|
|
1080
|
+
_, bid_volume, *_ = bid[0]
|
|
1081
|
+
if ask_price is None:
|
|
1082
|
+
ask_price, _, *_ = ask[0]
|
|
1083
|
+
if ask_volume is None:
|
|
1084
|
+
_, ask_volume, *_ = ask[0]
|
|
1085
|
+
|
|
999
1086
|
if bid_price is not None and math.isfinite(bid_price):
|
|
1000
1087
|
self['bid_price'] = bid_price
|
|
1001
1088
|
|
|
@@ -1008,16 +1095,10 @@ class TickData(MarketData):
|
|
|
1008
1095
|
if ask_volume is not None and math.isfinite(ask_volume):
|
|
1009
1096
|
self['ask_volume'] = ask_volume
|
|
1010
1097
|
|
|
1011
|
-
if order_book is not None:
|
|
1012
|
-
self['order_book'] = order_book
|
|
1013
|
-
|
|
1014
|
-
if kwargs:
|
|
1015
|
-
self['additional'] = dict(kwargs)
|
|
1016
|
-
|
|
1017
1098
|
@property
|
|
1018
1099
|
def level_2(self) -> OrderBook | None:
|
|
1019
1100
|
if 'order_book' in self:
|
|
1020
|
-
return OrderBook(**self['order_book'])
|
|
1101
|
+
return OrderBook(ticker=self.ticker, timestamp=self.timestamp, **self['order_book'])
|
|
1021
1102
|
else:
|
|
1022
1103
|
return None
|
|
1023
1104
|
|
|
@@ -18,6 +18,9 @@ class Profile(object, metaclass=abc.ABCMeta):
|
|
|
18
18
|
|
|
19
19
|
self.time_zone = None
|
|
20
20
|
|
|
21
|
+
def __repr__(self):
|
|
22
|
+
return f'<Profile {self.profile_id}>({id(self)})'
|
|
23
|
+
|
|
21
24
|
def override_profile(self, profile: Self = None) -> Self:
|
|
22
25
|
if profile is None:
|
|
23
26
|
profile = PROFILE
|
|
@@ -11,12 +11,12 @@ from ..profile import Profile, PROFILE
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
@overload
|
|
14
|
-
def ts_indices(market_date, interval, session_start, session_end, session_break, time_zone, ts_mode, ts_format='timestamp') -> list[float]:
|
|
14
|
+
def ts_indices(market_date, interval, session_start, session_end, session_break, time_zone, ts_mode: Literal['start', 'end', 'both'], ts_format='timestamp') -> list[float]:
|
|
15
15
|
...
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
@overload
|
|
19
|
-
def ts_indices(market_date, interval, session_start, session_end, session_break, time_zone, ts_mode, ts_format='datetime') -> list[datetime.datetime]:
|
|
19
|
+
def ts_indices(market_date, interval, session_start, session_end, session_break, time_zone, ts_mode: Literal['start', 'end', 'both'], ts_format='datetime') -> list[datetime.datetime]:
|
|
20
20
|
...
|
|
21
21
|
|
|
22
22
|
|
|
@@ -158,7 +158,8 @@ def fake_data(
|
|
|
158
158
|
session_start=session_start,
|
|
159
159
|
session_end=session_end,
|
|
160
160
|
session_break=session_break,
|
|
161
|
-
time_zone=time_zone
|
|
161
|
+
time_zone=time_zone,
|
|
162
|
+
ts_mode='end',
|
|
162
163
|
)
|
|
163
164
|
|
|
164
165
|
ttl_days = kwargs.get('ttl_days', 252)
|
|
File without changes
|
|
File without changes
|
{pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/PyAlgoEngine.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/apps/backtest/__init__.py
RENAMED
|
File without changes
|
{pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/apps/backtest/doc_server.py
RENAMED
|
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
|
{pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/base/technical_analysis.py
RENAMED
|
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
|
{pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/strategy/strategy_engine.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyalgoengine-0.5.4.post7 → pyalgoengine-0.5.4.post10}/algo_engine/utils/commit_regularizer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|