PyAlgoEngine 0.5.4.post6__tar.gz → 0.5.4.post8__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.
Files changed (45) hide show
  1. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/PKG-INFO +27 -27
  2. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/PyAlgoEngine.egg-info/PKG-INFO +27 -27
  3. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/__init__.py +1 -1
  4. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/base/__init__.py +1 -1
  5. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/base/market_utils.py +94 -19
  6. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/setup.cfg +4 -4
  7. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/LICENSE +0 -0
  8. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/PyAlgoEngine.egg-info/SOURCES.txt +0 -0
  9. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/PyAlgoEngine.egg-info/dependency_links.txt +0 -0
  10. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/PyAlgoEngine.egg-info/requires.txt +0 -0
  11. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/PyAlgoEngine.egg-info/top_level.txt +0 -0
  12. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/README.md +0 -0
  13. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/apps/__init__.py +0 -0
  14. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/apps/backtest/__init__.py +0 -0
  15. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/apps/backtest/doc_server.py +0 -0
  16. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/apps/backtest/tester.py +0 -0
  17. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/apps/backtest/web_app.py +0 -0
  18. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/apps/bokeh_server.py +0 -0
  19. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/apps/demo/__init__.py +0 -0
  20. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/apps/demo/test.py +0 -0
  21. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/backtest/__init__.py +0 -0
  22. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/backtest/__main__.py +0 -0
  23. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/backtest/metrics.py +0 -0
  24. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/backtest/replay.py +0 -0
  25. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/backtest/sim_match.py +0 -0
  26. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/base/console_utils.py +0 -0
  27. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/base/finance_decimal.py +0 -0
  28. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/base/technical_analysis.py +0 -0
  29. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/base/telemetrics.py +0 -0
  30. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/base/trade_utils.py +0 -0
  31. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/engine/__init__.py +0 -0
  32. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/engine/algo_engine.py +0 -0
  33. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/engine/event_engine.py +0 -0
  34. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/engine/market_engine.py +0 -0
  35. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/engine/trade_engine.py +0 -0
  36. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/monitor/__init__.py +0 -0
  37. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/monitor/advanced_data_interface.py +0 -0
  38. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/profile/__init__.py +0 -0
  39. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/profile/cn.py +0 -0
  40. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/strategy/__init__.py +0 -0
  41. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/strategy/strategy_engine.py +0 -0
  42. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/utils/__init__.py +0 -0
  43. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/utils/commit_regularizer.py +0 -0
  44. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/algo_engine/utils/data_utils.py +0 -0
  45. {pyalgoengine-0.5.4.post6 → pyalgoengine-0.5.4.post8}/setup.py +0 -0
@@ -1,27 +1,27 @@
1
- Metadata-Version: 2.1
2
- Name: PyAlgoEngine
3
- Version: 0.5.4.post6
4
- Summary: Basic algo engine
5
- Home-page: https://github.com/BolunHan/PyAlgoEngine
6
- Author: Bolun.Han
7
- Author-email: Bolun.Han@outlook.com
8
- Classifier: Programming Language :: Python :: 3.8
9
- Classifier: Programming Language :: Python :: 3.9
10
- Classifier: Programming Language :: Python :: 3.10
11
- Classifier: Programming Language :: Python :: 3.11
12
- Classifier: Programming Language :: Python :: 3.12
13
- Classifier: Operating System :: OS Independent
14
- Requires-Python: >=3.1
15
- Description-Content-Type: text/markdown
16
- License-File: LICENSE
17
- Requires-Dist: numpy
18
- Requires-Dist: pandas
19
- Requires-Dist: exchange_calendars
20
- Requires-Dist: PyEventEngine
21
- Provides-Extra: webapps
22
- Requires-Dist: flask; extra == "webapps"
23
- Requires-Dist: waitress; extra == "webapps"
24
- Requires-Dist: bokeh; extra == "webapps"
25
-
26
- # PyAlgoEngine
27
- python algo trading engine
1
+ Metadata-Version: 2.1
2
+ Name: PyAlgoEngine
3
+ Version: 0.5.4.post8
4
+ Summary: Basic algo engine
5
+ Home-page: https://github.com/BolunHan/PyAlgoEngine
6
+ Author: Bolun.Han
7
+ Author-email: Bolun.Han@outlook.com
8
+ Classifier: Programming Language :: Python :: 3.8
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.1
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: numpy
18
+ Requires-Dist: pandas
19
+ Requires-Dist: exchange_calendars
20
+ Requires-Dist: PyEventEngine
21
+ Provides-Extra: webapps
22
+ Requires-Dist: flask; extra == "webapps"
23
+ Requires-Dist: waitress; extra == "webapps"
24
+ Requires-Dist: bokeh; extra == "webapps"
25
+
26
+ # PyAlgoEngine
27
+ python algo trading engine
@@ -1,27 +1,27 @@
1
- Metadata-Version: 2.1
2
- Name: PyAlgoEngine
3
- Version: 0.5.4.post6
4
- Summary: Basic algo engine
5
- Home-page: https://github.com/BolunHan/PyAlgoEngine
6
- Author: Bolun.Han
7
- Author-email: Bolun.Han@outlook.com
8
- Classifier: Programming Language :: Python :: 3.8
9
- Classifier: Programming Language :: Python :: 3.9
10
- Classifier: Programming Language :: Python :: 3.10
11
- Classifier: Programming Language :: Python :: 3.11
12
- Classifier: Programming Language :: Python :: 3.12
13
- Classifier: Operating System :: OS Independent
14
- Requires-Python: >=3.1
15
- Description-Content-Type: text/markdown
16
- License-File: LICENSE
17
- Requires-Dist: numpy
18
- Requires-Dist: pandas
19
- Requires-Dist: exchange_calendars
20
- Requires-Dist: PyEventEngine
21
- Provides-Extra: webapps
22
- Requires-Dist: flask; extra == "webapps"
23
- Requires-Dist: waitress; extra == "webapps"
24
- Requires-Dist: bokeh; extra == "webapps"
25
-
26
- # PyAlgoEngine
27
- python algo trading engine
1
+ Metadata-Version: 2.1
2
+ Name: PyAlgoEngine
3
+ Version: 0.5.4.post8
4
+ Summary: Basic algo engine
5
+ Home-page: https://github.com/BolunHan/PyAlgoEngine
6
+ Author: Bolun.Han
7
+ Author-email: Bolun.Han@outlook.com
8
+ Classifier: Programming Language :: Python :: 3.8
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.1
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: numpy
18
+ Requires-Dist: pandas
19
+ Requires-Dist: exchange_calendars
20
+ Requires-Dist: PyEventEngine
21
+ Provides-Extra: webapps
22
+ Requires-Dist: flask; extra == "webapps"
23
+ Requires-Dist: waitress; extra == "webapps"
24
+ Requires-Dist: bokeh; extra == "webapps"
25
+
26
+ # PyAlgoEngine
27
+ python algo trading engine
@@ -1,4 +1,4 @@
1
- __version__ = "0.5.4.post6"
1
+ __version__ = "0.5.4.post8"
2
2
 
3
3
  import logging
4
4
  import os
@@ -22,7 +22,7 @@ from .console_utils import Progress, GetInput, GetArgs, count_ordinal, TerminalS
22
22
 
23
23
  __all__ = ['PROFILE',
24
24
  'FinancialDecimal',
25
- 'TransactionSide', 'MarketData', 'OrderBook', 'BarData', 'TickData', 'TransactionData', 'TradeData', 'OrderBookBuffer', 'BarDataBuffer', 'TickDataBuffer', 'TransactionDataBuffer',
25
+ 'TransactionSide', 'MarketData', 'OrderBook', 'BarData', 'DailyBar', 'CandleStick', 'TickData', 'TransactionData', 'TradeData', 'OrderBookBuffer', 'BarDataBuffer', 'TickDataBuffer', 'TransactionDataBuffer',
26
26
  'TechnicalAnalysis',
27
27
  'OrderState', 'OrderType', 'TradeInstruction', 'TradeReport',
28
28
  'Progress', 'GetInput', 'GetArgs', 'count_ordinal', 'TerminalStyle', 'InteractiveShell', 'ShellTransfer']
@@ -9,8 +9,9 @@ import re
9
9
  import warnings
10
10
  from ctypes import c_ulong, c_double, c_wchar, c_int, c_longlong
11
11
  from multiprocessing import RawValue, RawArray
12
- from typing import overload
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
@@ -733,7 +734,7 @@ class BarData(MarketData):
733
734
  raise ValueError(f'Invalid bar_span, expect int, float or timedelta, got {bar_span}')
734
735
 
735
736
  def __repr__(self):
736
- return f'<BarData>([{self.market_time:%Y-%m-%d %H:%M:%S}] {self.ticker}, open={self.open_price}, close={self.close_price}, high={self.high_price}, low={self.low_price})'
737
+ return f'<{self.__class__.__name__}>([{self.market_time:%Y-%m-%d %H:%M:%S}] {self.ticker}, open={self.open_price}, close={self.close_price}, high={self.high_price}, low={self.low_price})'
737
738
 
738
739
  @classmethod
739
740
  def from_json(cls, json_message: str | bytes | bytearray | dict) -> BarData:
@@ -864,28 +865,21 @@ class BarData(MarketData):
864
865
  return self.close_price
865
866
 
866
867
  @property
867
- def bar_type(self):
868
- if self.bar_span > datetime.timedelta(days=1):
869
- return 'Over-Daily'
870
- elif self.bar_span == datetime.timedelta(days=1):
871
- return 'Daily'
872
- elif self.bar_span > datetime.timedelta(hours=1):
873
- return 'Over-Hourly'
874
- elif self.bar_span == datetime.timedelta(hours=1):
868
+ def bar_type(self) -> Literal['Hourly-Plus', 'Hourly', 'Minute-Plus', 'Minute', 'Sub-Minute']:
869
+ if self['bar_span'] > 3600:
870
+ return 'Hourly-Plus'
871
+ elif self['bar_span'] == 3600:
875
872
  return 'Hourly'
876
- elif self.bar_span > datetime.timedelta(minutes=1):
877
- return 'Over-Minute'
878
- elif self.bar_span == datetime.timedelta(minutes=1):
873
+ elif self['bar_span'] > 60:
874
+ return 'Minute-Plus'
875
+ elif self['bar_span'] == 60:
879
876
  return 'Minute'
880
877
  else:
881
878
  return 'Sub-Minute'
882
879
 
883
880
  @property
884
881
  def bar_end_time(self) -> datetime.datetime | datetime.date:
885
- if self.bar_type == 'Daily':
886
- return self.market_time.date()
887
- else:
888
- return self.market_time
882
+ return self.market_time
889
883
 
890
884
 
891
885
  # alias of the BarData
@@ -896,7 +890,7 @@ class DailyBar(BarData):
896
890
  def __init__(
897
891
  self, *,
898
892
  ticker: str,
899
- market_date: datetime.date, # The market date of the bar, if with 1D data, or the END date of the bar.
893
+ market_date: datetime.date | str, # The market date of the bar, if with 1D data, or the END date of the bar.
900
894
  timestamp: float = None,
901
895
  start_date: datetime.date = None,
902
896
  bar_span: datetime.timedelta | int = None, # expect to be a timedelta for several days, or the number of days
@@ -909,6 +903,9 @@ class DailyBar(BarData):
909
903
  trade_count: int = 0,
910
904
  **kwargs
911
905
  ):
906
+ if isinstance(market_date, str):
907
+ market_date = datetime.date.fromisoformat(market_date)
908
+
912
909
  if bar_span is None and start_date is None:
913
910
  raise ValueError('Must assign ether datetime.date or bar_span or both.')
914
911
  elif start_date is None:
@@ -923,9 +920,15 @@ class DailyBar(BarData):
923
920
  else:
924
921
  assert (market_date - start_date).days == bar_span.days
925
922
 
923
+ if timestamp is None:
924
+ if PROFILE.session_end is None:
925
+ timestamp = datetime.datetime.combine(market_date, datetime.time.min, tzinfo=PROFILE.time_zone).timestamp()
926
+ else:
927
+ timestamp = datetime.datetime.combine(market_date, PROFILE.session_end, tzinfo=PROFILE.time_zone).timestamp()
928
+
926
929
  super().__init__(
927
930
  ticker=ticker,
928
- timestamp=datetime.datetime.combine(market_date, datetime.time.min).timestamp() if timestamp is None else timestamp,
931
+ timestamp=timestamp,
929
932
  bar_span=bar_span,
930
933
  high_price=high_price,
931
934
  low_price=low_price,
@@ -939,6 +942,57 @@ class DailyBar(BarData):
939
942
 
940
943
  self['market_date'] = market_date
941
944
 
945
+ def __repr__(self):
946
+ 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})'
947
+
948
+ def to_json(self, fmt='str', **kwargs) -> str | dict:
949
+ data_dict = super().to_json(fmt='dict', **kwargs)
950
+
951
+ data_dict['market_date'] = self.market_date.isoformat()
952
+
953
+ if fmt == 'dict':
954
+ return data_dict
955
+ elif fmt == 'str':
956
+ return json.dumps(data_dict, **kwargs)
957
+ else:
958
+ raise ValueError(f'Invalid format {fmt}, except "dict" or "str".')
959
+
960
+ def to_list(self) -> list[float | int | str | bool]:
961
+ return [self.__class__.__name__,
962
+ self.ticker,
963
+ self.market_date.isoformat(),
964
+ self.timestamp,
965
+ self.high_price,
966
+ self.low_price,
967
+ self.open_price,
968
+ self.close_price,
969
+ self['bar_span'],
970
+ self.volume,
971
+ self.notional,
972
+ self.trade_count]
973
+
974
+ @classmethod
975
+ def from_list(cls, data_list: list[float | int | str | bool]) -> BarData:
976
+ (dtype, ticker, market_date, timestamp, high_price, low_price, open_price, close_price,
977
+ bar_span, volume, notional, trade_count) = data_list
978
+
979
+ if dtype != cls.__name__:
980
+ raise TypeError(f'dtype mismatch, expect {cls.__name__}, got {dtype}.')
981
+
982
+ return cls(
983
+ ticker=ticker,
984
+ market_date=market_date,
985
+ timestamp=timestamp,
986
+ high_price=high_price,
987
+ low_price=low_price,
988
+ open_price=open_price,
989
+ close_price=close_price,
990
+ bar_span=datetime.timedelta(bar_span) if bar_span else None,
991
+ volume=volume,
992
+ notional=notional,
993
+ trade_count=trade_count
994
+ )
995
+
942
996
  @property
943
997
  def bar_span(self) -> datetime.timedelta:
944
998
  return datetime.timedelta(days=self['bar_span'])
@@ -947,6 +1001,27 @@ class DailyBar(BarData):
947
1001
  def market_date(self) -> datetime.date:
948
1002
  return self['market_date']
949
1003
 
1004
+ @property
1005
+ def market_time(self) -> datetime.date:
1006
+ return self.market_date
1007
+
1008
+ @property
1009
+ def bar_start_time(self) -> datetime.date:
1010
+ return self.market_date - self.bar_span
1011
+
1012
+ @property
1013
+ def bar_end_time(self) -> datetime.date:
1014
+ return self.market_date
1015
+
1016
+ @property
1017
+ def bar_type(self) -> Literal['Daily', 'Daily-Plus']:
1018
+ if self['bar_span'] == 1:
1019
+ return 'Daily'
1020
+ elif self['bar_span'] > 1:
1021
+ return 'Daily-Plus'
1022
+ else:
1023
+ raise ValueError(f'Invalid bar_span for {self.__class__.__name__}! Expect a int greater or equal to 1, got {self["bar_span"]}')
1024
+
950
1025
 
951
1026
  class TickData(MarketData):
952
1027
  def __init__(
@@ -1,4 +1,4 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+