quantification 0.1.0__py3-none-any.whl → 0.1.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.
Files changed (78) hide show
  1. quantification/__init__.py +3 -2
  2. quantification/api/__init__.py +3 -0
  3. quantification/api/akshare/__init__.py +1 -0
  4. quantification/api/akshare/akshare.py +17 -0
  5. quantification/api/akshare/delegate/__init__.py +6 -0
  6. quantification/api/akshare/delegate/macro_china_fdi.py +46 -0
  7. quantification/api/akshare/delegate/macro_china_lpr.py +43 -0
  8. quantification/api/akshare/delegate/macro_china_qyspjg.py +51 -0
  9. quantification/api/akshare/delegate/macro_china_shrzgm.py +47 -0
  10. quantification/api/akshare/delegate/macro_cnbs.py +47 -0
  11. quantification/api/akshare/delegate/stock_zh_a_hist.py +77 -0
  12. quantification/api/akshare/setting.py +5 -0
  13. quantification/api/api.py +11 -0
  14. quantification/api/api.pyi +21 -0
  15. quantification/api/tushare/__init__.py +1 -0
  16. quantification/api/tushare/delegate/__init__.py +7 -0
  17. quantification/api/tushare/delegate/balancesheet.py +66 -0
  18. quantification/api/tushare/delegate/cashflow.py +29 -0
  19. quantification/api/tushare/delegate/common.py +64 -0
  20. quantification/api/tushare/delegate/daily_basic.py +81 -0
  21. quantification/api/tushare/delegate/fina_indicator.py +20 -0
  22. quantification/api/tushare/delegate/income.py +34 -0
  23. quantification/api/tushare/delegate/index_daily.py +61 -0
  24. quantification/api/tushare/delegate/pro_bar.py +80 -0
  25. quantification/api/tushare/setting.py +5 -0
  26. quantification/api/tushare/tushare.py +17 -0
  27. quantification/core/__init__.py +9 -0
  28. quantification/core/asset/__init__.py +6 -0
  29. quantification/core/asset/base_asset.py +96 -0
  30. quantification/core/asset/base_broker.py +42 -0
  31. quantification/core/asset/broker.py +108 -0
  32. quantification/core/asset/cash.py +75 -0
  33. quantification/core/asset/stock.py +268 -0
  34. quantification/core/cache.py +93 -0
  35. quantification/core/configure.py +15 -0
  36. quantification/core/data/__init__.py +5 -0
  37. quantification/core/data/base_api.py +109 -0
  38. quantification/core/data/base_delegate.py +73 -0
  39. quantification/core/data/field.py +213 -0
  40. quantification/core/data/panel.py +42 -0
  41. quantification/core/env.py +25 -0
  42. quantification/core/logger.py +94 -0
  43. quantification/core/strategy/__init__.py +3 -0
  44. quantification/core/strategy/base_strategy.py +66 -0
  45. quantification/core/strategy/base_trigger.py +69 -0
  46. quantification/core/strategy/base_use.py +69 -0
  47. quantification/core/trader/__init__.py +7 -0
  48. quantification/core/trader/base_order.py +45 -0
  49. quantification/core/trader/base_stage.py +16 -0
  50. quantification/core/trader/base_trader.py +173 -0
  51. quantification/core/trader/collector.py +47 -0
  52. quantification/core/trader/order.py +23 -0
  53. quantification/core/trader/portfolio.py +72 -0
  54. quantification/core/trader/query.py +29 -0
  55. quantification/core/trader/report.py +76 -0
  56. quantification/core/util.py +181 -0
  57. quantification/default/__init__.py +5 -0
  58. quantification/default/stage/__init__.py +1 -0
  59. quantification/default/stage/cn_stock.py +23 -0
  60. quantification/default/strategy/__init__.py +1 -0
  61. quantification/default/strategy/simple/__init__.py +1 -0
  62. quantification/default/strategy/simple/strategy.py +8 -0
  63. quantification/default/trader/__init__.py +2 -0
  64. quantification/default/trader/a_factor/__init__.py +1 -0
  65. quantification/default/trader/a_factor/trader.py +27 -0
  66. quantification/default/trader/simple/__init__.py +1 -0
  67. quantification/default/trader/simple/trader.py +8 -0
  68. quantification/default/trigger/__init__.py +1 -0
  69. quantification/default/trigger/trigger.py +63 -0
  70. quantification/default/use/__init__.py +1 -0
  71. quantification/default/use/factors/__init__.py +2 -0
  72. quantification/default/use/factors/factor.py +205 -0
  73. quantification/default/use/factors/use.py +38 -0
  74. quantification-0.1.1.dist-info/METADATA +19 -0
  75. quantification-0.1.1.dist-info/RECORD +76 -0
  76. {quantification-0.1.0.dist-info → quantification-0.1.1.dist-info}/WHEEL +1 -1
  77. quantification-0.1.0.dist-info/METADATA +0 -13
  78. quantification-0.1.0.dist-info/RECORD +0 -4
@@ -0,0 +1,213 @@
1
+ from enum import Enum, auto
2
+
3
+
4
+ class Field(Enum):
5
+ """
6
+ ----------------------------------------------------------------
7
+ 股票 ST
8
+ ----------------------------------------------------------------
9
+ """
10
+ ST_开盘价 = auto()
11
+ ST_最高价 = auto()
12
+ ST_最低价 = auto()
13
+ ST_收盘价 = auto()
14
+ ST_昨收价 = auto() # 后复权
15
+ ST_涨跌额 = auto()
16
+ ST_涨跌幅 = auto() # 后复权
17
+ ST_成交量 = auto()
18
+ ST_成交额 = auto() # 万元
19
+ ST_振幅 = auto()
20
+ ST_换手率 = auto()
21
+ ST_自由流通股换手率 = auto()
22
+ ST_量比 = auto()
23
+ ST_总市值 = auto()
24
+ ST_流通市值 = auto()
25
+
26
+ """
27
+ ----------------------------------------------------------------
28
+ 利润表 IS
29
+ ----------------------------------------------------------------
30
+ """
31
+ IS_营业总收入 = auto()
32
+ IS_营业总成本 = auto()
33
+ IS_营业利润 = auto()
34
+ IS_利润总额 = auto()
35
+ IS_息税前利润 = auto()
36
+ IS_息税折旧摊销前利润 = auto()
37
+ IS_所得税费用 = auto()
38
+ IS_净利润 = auto()
39
+ IS_归母净利润 = auto()
40
+ IS_综合收益 = auto()
41
+ IS_归母综合收益 = auto()
42
+
43
+ IS_销售费用 = auto()
44
+ IS_管理费用 = auto()
45
+ IS_财务费用 = auto()
46
+ IS_研发费用 = auto()
47
+
48
+ """
49
+ ----------------------------------------------------------------
50
+ 资产负债表 BS
51
+ ----------------------------------------------------------------
52
+ """
53
+ BS_总股本 = auto()
54
+ BS_库存股 = auto()
55
+ BS_资本公积 = auto()
56
+ BS_盈余公积 = auto()
57
+ BS_未分配利润 = auto()
58
+ BS_股东权益合计 = auto()
59
+ BS_归母股东权益合计 = auto()
60
+
61
+ BS_货币资金 = auto()
62
+ BS_交易性金融资产 = auto()
63
+ BS_应收票据 = auto()
64
+ BS_应收账款 = auto()
65
+ BS_应收股利 = auto()
66
+ BS_应收利息 = auto()
67
+ BS_其他应收款 = auto()
68
+ BS_预付款项 = auto()
69
+ BS_存货 = auto()
70
+ BS_一年内到期的非流动资产 = auto()
71
+ BS_可供出售金融资产 = auto()
72
+ BS_持有至到期投资 = auto()
73
+ BS_长期股权投资 = auto()
74
+ BS_投资性房地产 = auto()
75
+ BS_定期存款 = auto()
76
+ BS_长期应收款 = auto()
77
+ BS_固定资产 = auto()
78
+ BS_在建工程 = auto()
79
+ BS_无形资产 = auto()
80
+ BS_研发支出 = auto()
81
+ BS_商誉 = auto()
82
+ BS_流动资产合计 = auto()
83
+ BS_非流动资产合计 = auto()
84
+ BS_资产合计 = auto()
85
+
86
+ BS_短期借款 = auto()
87
+ BS_长期借款 = auto()
88
+ BS_交易性金融负债 = auto()
89
+ BS_应付票据 = auto()
90
+ BS_应付账款 = auto()
91
+ BS_应付职工薪酬 = auto()
92
+ BS_应付利息 = auto()
93
+ BS_应付股利 = auto()
94
+ BS_应付短期债券 = auto()
95
+ BS_应付债券 = auto()
96
+ BS_长期应付款 = auto()
97
+ BS_预收款项 = auto()
98
+ BS_一年内到期的非流动负债 = auto()
99
+ BS_流动负债合计 = auto()
100
+ BS_非流动负债合计 = auto()
101
+ BS_负债合计 = auto()
102
+
103
+ """
104
+ ----------------------------------------------------------------
105
+ 现金流量表 CS
106
+ ----------------------------------------------------------------
107
+ """
108
+ CS_经营活动现金流入 = auto()
109
+ CS_经营活动现金流出 = auto()
110
+ CS_经营活动净现金流 = auto()
111
+
112
+ CS_投资活动现金流入 = auto()
113
+ CS_投资活动现金流出 = auto()
114
+ CS_投资活动净现金流 = auto()
115
+
116
+ CS_筹资活动现金流入 = auto()
117
+ CS_筹资活动现金流出 = auto()
118
+ CS_筹资活动净现金流 = auto()
119
+
120
+ CS_现金及现金等价物净增加额 = auto()
121
+
122
+ """
123
+ ----------------------------------------------------------------
124
+ 财务指标 FI
125
+ ----------------------------------------------------------------
126
+ """
127
+
128
+ FI_净资产收益率 = auto()
129
+
130
+ """
131
+ ----------------------------------------------------------------
132
+ 指数 IN
133
+ ----------------------------------------------------------------
134
+ """
135
+ IN_开盘点位 = auto()
136
+ IN_收盘点位 = auto()
137
+ IN_最高点位 = auto()
138
+ IN_最低点位 = auto()
139
+
140
+ """
141
+ ----------------------------------------------------------------
142
+ 杠杆率 LEV
143
+ ----------------------------------------------------------------
144
+ """
145
+ LEV_居民部门 = auto() # 注意单位: %
146
+ LEV_非金融企业部门 = auto() # 注意单位: %
147
+ LEV_政府部门 = auto() # 注意单位: %
148
+ LEV_中央政府 = auto() # 注意单位: %
149
+ LEV_地方政府 = auto() # 注意单位: %
150
+ LEV_实体经济部门 = auto() # 注意单位: %
151
+ LEV_金融部门资产方 = auto() # 注意单位: %
152
+ LEV_金融部门负债方 = auto() # 注意单位: %
153
+
154
+ """
155
+ ----------------------------------------------------------------
156
+ 企业商品交易价格指数 CGPI
157
+ ----------------------------------------------------------------
158
+ """
159
+ CGPI_总指数 = auto()
160
+ CGPI_总指数同比增长 = auto() # 注意单位: %
161
+ CGPI_总指数环比增长 = auto() # 注意单位: %
162
+ CGPI_农产品 = auto()
163
+ CGPI_农产品同比增长 = auto() # 注意单位: %
164
+ CGPI_农产品环比增长 = auto() # 注意单位: %
165
+ CGPI_矿产品 = auto()
166
+ CGPI_矿产品同比增长 = auto() # 注意单位: %
167
+ CGPI_矿产品环比增长 = auto() # 注意单位: %
168
+ CGPI_煤油电 = auto()
169
+ CGPI_煤油电同比增长 = auto() # 注意单位: %
170
+ CGPI_煤油电环比增长 = auto() # 注意单位: %
171
+
172
+ """
173
+ ----------------------------------------------------------------
174
+ 国际直接投资 FDI
175
+ ----------------------------------------------------------------
176
+ """
177
+ FDI_当月 = auto() # 注意单位: 万美元
178
+ FDI_当月同比增长 = auto() # 注意单位: %
179
+ FDI_当月环比增长 = auto() # 注意单位: %
180
+ FDI_累计 = auto() # 注意单位: 万美元
181
+ FDI_累计同比增长 = auto() # 注意单位: %
182
+
183
+ """
184
+ ----------------------------------------------------------------
185
+ 利率 RATE
186
+ ----------------------------------------------------------------
187
+ """
188
+ RATE_LPR1年 = auto() # 注意单位: %
189
+ RATE_LPR5年 = auto() # 注意单位: %
190
+ RATE_短期贷款 = auto() # 注意单位: %
191
+ RATE_中长期贷款 = auto() # 注意单位: %
192
+
193
+ """
194
+ ----------------------------------------------------------------
195
+ 社会融资规模 AFRE
196
+ ----------------------------------------------------------------
197
+ """
198
+ AFRE_总增量 = auto() # 注意单位: 亿元
199
+ AFRE_人民币贷款增量 = auto() # 注意单位: 亿元
200
+ AFRE_委托贷款外币贷款增量 = auto() # 注意单位: 折合人民币, 亿元
201
+ AFRE_委托贷款增量 = auto() # 注意单位: 亿元
202
+ AFRE_信托贷款增量 = auto() # 注意单位: 亿元
203
+ AFRE_未贴现银行承兑汇票增量 = auto() # 注意单位: 亿元
204
+ AFRE_企业债券增量 = auto() # 注意单位: 亿元
205
+ AFRE_非金融企业境内股票融资增量 = auto() # 注意单位: 亿元
206
+
207
+ def __repr__(self):
208
+ return self.name
209
+
210
+ __str__ = __repr__
211
+
212
+
213
+ __all__ = ["Field"]
@@ -0,0 +1,42 @@
1
+ from datetime import datetime
2
+
3
+ import pandas as pd
4
+
5
+ from .field import Field
6
+
7
+
8
+ class DataPanel(pd.DataFrame):
9
+ def __init__(self, data: pd.DataFrame = None, mask: pd.DataFrame = None):
10
+ data = data if data is not None else pd.DataFrame()
11
+ mask = mask if mask is not None else pd.DataFrame()
12
+ self.mask = mask
13
+ super().__init__(data)
14
+
15
+ if self.shape[0] != 0:
16
+ assert type(self.index) == pd.DatetimeIndex, \
17
+ f"DataPanel data的索引必须为pd.DatetimeIndex, 实际为{type(self.index)}"
18
+
19
+ for col in self.columns:
20
+ assert type(col) == Field, \
21
+ f"DataPanel data的列必须为core.Field, {col}实际为{type(col)}"
22
+
23
+ if self.mask.shape[0] != 0:
24
+ assert type(self.index) == pd.DatetimeIndex, \
25
+ f"DataPanel mask的索引必须为pd.DatetimeIndex, 实际为{type(self.index)}"
26
+
27
+ for col in self.columns:
28
+ assert type(col) == Field, \
29
+ f"DataPanel mask的列必须为core.Field, {col}实际为{type(col)}"
30
+
31
+ assert self.columns.equals(self.mask.columns) and self.shape == self.mask.shape, \
32
+ f"DataPanel data与mask的结构不一致, data:\n{self}\nmask:\n{self.mask} "
33
+
34
+ def __lshift__(self, other: "DataPanel"):
35
+ assert isinstance(other, DataPanel), f"DataPanel只能与DataPanel进行lshift操作, 实际为{type(other)}"
36
+ return DataPanel(self.join(other, how='outer'), self.mask.join(other.mask, how='outer'))
37
+
38
+ def on(self, d: datetime) -> pd.DataFrame:
39
+ return self.where((self.mask <= d) | self.isna(), other="invalid")[:d.date()]
40
+
41
+
42
+ __all__ = ["DataPanel"]
@@ -0,0 +1,25 @@
1
+ import datetime
2
+ from abc import ABCMeta
3
+ from dataclasses import dataclass
4
+
5
+ from typing import Callable
6
+
7
+
8
+ @dataclass
9
+ class Env:
10
+ date: datetime.date
11
+ time: datetime.time
12
+
13
+
14
+ class EnvGetter(metaclass=ABCMeta):
15
+ getter: Callable[[], Env] | None = None
16
+
17
+ @property
18
+ def env(self) -> Env | None:
19
+ if self.__class__.getter is not None:
20
+ return self.__class__.getter()
21
+
22
+ return None
23
+
24
+
25
+ __all__ = ['EnvGetter', "Env"]
@@ -0,0 +1,94 @@
1
+ import sys
2
+ from datetime import datetime
3
+
4
+ from loguru import logger as _logger
5
+ from pydantic import BaseModel
6
+ from loguru._datetime import datetime as _datetime
7
+
8
+ from .env import EnvGetter
9
+ from .configure import config
10
+
11
+
12
+ class Record(BaseModel):
13
+ file: str
14
+ func: str
15
+ line: int
16
+ level: str
17
+ message: str
18
+
19
+
20
+ class Logger(EnvGetter):
21
+ def __init__(self):
22
+ super().__init__()
23
+
24
+ _logger.remove()
25
+ _logger.add(
26
+ sink=self.sink,
27
+ colorize=True, # 在支持颜色的终端显示彩色日志
28
+ backtrace=True, # 记录异常堆栈
29
+ diagnose=True, # 显示变量值
30
+ level=config.log_level,
31
+ format=(
32
+ "<g>{time:YYYY-MM-DD HH:mm:ss}</g> "
33
+ "[<lvl>{level:^7}</lvl>] "
34
+ "|函数 <r><u>{function}</u></r>: <c>{line}</c>行| "
35
+ "{message}"
36
+ ),
37
+ )
38
+
39
+ self.records: dict[str, list[Record]] = {}
40
+
41
+ def sink(self, message):
42
+ if not self.env:
43
+ return
44
+
45
+ sys.stdout.write(message)
46
+ sys.stdout.flush()
47
+
48
+ datetime_str = message.record["time"].isoformat()
49
+ if datetime_str not in self.records:
50
+ self.records[datetime_str] = []
51
+
52
+ self.records[datetime_str].append(Record(
53
+ file=message.record["file"].name,
54
+ func=message.record["function"],
55
+ line=message.record["line"],
56
+ level=message.record["level"].name,
57
+ message=message.record["message"]
58
+ ))
59
+
60
+ def hijack(self):
61
+ if env := self.env:
62
+ current = datetime.combine(env.date, env.time)
63
+ else:
64
+ current = datetime.now()
65
+ return _logger.opt(depth=1).patch(lambda r: r.update(time=_datetime(
66
+ year=current.year,
67
+ month=current.month,
68
+ day=current.day,
69
+ hour=current.hour,
70
+ minute=current.minute,
71
+ )))
72
+
73
+ def trace(self, msg):
74
+ self.hijack().trace(msg)
75
+
76
+ def debug(self, msg):
77
+ self.hijack().debug(msg)
78
+
79
+ def success(self, msg):
80
+ self.hijack().success(msg)
81
+
82
+ def info(self, msg):
83
+ self.hijack().info(msg)
84
+
85
+ def warning(self, msg):
86
+ self.hijack().warning(msg)
87
+
88
+ def error(self, msg):
89
+ self.hijack().error(msg)
90
+
91
+
92
+ logger = Logger()
93
+
94
+ __all__ = ["logger", "Record"]
@@ -0,0 +1,3 @@
1
+ from .base_use import Use, Injection, WrappedFunc, Func
2
+ from .base_trigger import Trigger, Condition
3
+ from .base_strategy import BaseStrategy
@@ -0,0 +1,66 @@
1
+ from typing import Any
2
+
3
+ from .base_use import WrappedFunc, Func
4
+ from .base_trigger import Trigger
5
+
6
+
7
+ class Hook:
8
+ def __init__(
9
+ self,
10
+ func: WrappedFunc,
11
+ *,
12
+ once: bool = False,
13
+ ):
14
+ self.func = func
15
+ self.once = once
16
+ self.triggered = False
17
+
18
+ @property
19
+ def active(self) -> bool:
20
+ if self.once:
21
+ return not self.triggered
22
+
23
+ return True
24
+
25
+ def __call__(self, **kwargs):
26
+ self.triggered = True
27
+ return self.func(**kwargs)
28
+
29
+ def __repr__(self) -> str:
30
+ return f"<Hook {self.func}>"
31
+
32
+ __str__ = __repr__
33
+
34
+
35
+ class BaseStrategy:
36
+ def __init__(self):
37
+ self.context: dict[str, Any] = {}
38
+ self.hooks: dict[Trigger, list[Hook]] = {}
39
+
40
+ def on(self, trigger: Trigger, *, once: bool = False):
41
+ def wrapper(func: Func | WrappedFunc) -> WrappedFunc:
42
+ wrapped_func = func if isinstance(func, WrappedFunc) else WrappedFunc(func)
43
+
44
+ if not self.hooks.get(trigger):
45
+ self.hooks[trigger] = []
46
+
47
+ self.hooks[trigger].append(Hook(wrapped_func, once=once))
48
+
49
+ return wrapped_func
50
+
51
+ return wrapper
52
+
53
+ def triggered(self, **kwargs) -> list[Hook]:
54
+ triggered_hooks: list[Hook] = []
55
+ for trigger, hooks in self.hooks.items():
56
+ if not trigger.fulfilled(**kwargs):
57
+ continue
58
+
59
+ for hook in hooks:
60
+ if hook.active:
61
+ triggered_hooks.append(hook)
62
+
63
+ return triggered_hooks
64
+
65
+
66
+ __all__ = ["BaseStrategy"]
@@ -0,0 +1,69 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from ..util import inject
4
+
5
+
6
+ class Condition(ABC):
7
+ @abstractmethod
8
+ def __call__(self, **kwargs):
9
+ raise NotImplementedError
10
+
11
+ @abstractmethod
12
+ def name(self) -> str:
13
+ raise NotImplementedError
14
+
15
+ def settle(self, **kwargs):
16
+ ...
17
+
18
+ def __repr__(self):
19
+ return f"Condition({self.name()})"
20
+
21
+ __str__ = __repr__
22
+
23
+
24
+ class Trigger:
25
+ def __init__(self, *conditions: Condition):
26
+ self.conditions = conditions
27
+
28
+ def fulfilled(self, **kwargs) -> bool:
29
+ is_fulfilled = all([inject(condition, **kwargs) for condition in self.conditions])
30
+
31
+ if not is_fulfilled:
32
+ return False
33
+
34
+ for condition in self.conditions:
35
+ inject(condition.settle, **kwargs)
36
+
37
+ return True
38
+
39
+ def __and__(self, other):
40
+ if other is None:
41
+ return self
42
+
43
+ if isinstance(other, Trigger):
44
+ return Trigger(*self.conditions, *other.conditions)
45
+
46
+ raise NotImplementedError(f"不支持合并条件{other}")
47
+
48
+ def __rand__(self, other):
49
+ if other is None:
50
+ return self
51
+
52
+ if isinstance(other, Trigger):
53
+ return Trigger(*other.conditions, *self.conditions)
54
+
55
+ raise NotImplementedError(f"不支持合并条件{other}")
56
+
57
+ def __or__(self, other):
58
+ raise NotImplementedError(f"不支持or运算")
59
+
60
+ def __call__(self, *args, **kwargs):
61
+ return self
62
+
63
+ def __repr__(self):
64
+ return f"<Trigger {self.conditions}>"
65
+
66
+ __str__ = __repr__
67
+
68
+
69
+ __all__ = ["Trigger", "Condition"]
@@ -0,0 +1,69 @@
1
+ import inspect
2
+ from abc import ABC, abstractmethod
3
+ from typing import Generator, Callable, TYPE_CHECKING
4
+
5
+ from ..util import inject
6
+
7
+ if TYPE_CHECKING:
8
+ from ..trader import BaseOrder, Result
9
+
10
+ OrderGenerator = Generator["BaseOrder", "Result", None]
11
+ CommonFunc = Callable[..., None]
12
+ GeneratorFunc = Callable[..., OrderGenerator]
13
+ Func = CommonFunc | GeneratorFunc
14
+
15
+
16
+ class Injection(ABC):
17
+ name: str
18
+
19
+ @abstractmethod
20
+ def __init__(self, *args, **kwargs) -> None:
21
+ raise NotImplementedError
22
+
23
+ def __init_subclass__(cls, **kwargs):
24
+ assert hasattr(cls, "name"), \
25
+ "Injection类需要指定参数名"
26
+
27
+ assert isinstance(cls.name, str), \
28
+ "Injection指定的参数名必须为str"
29
+
30
+ @abstractmethod
31
+ def __call__(self, **kwargs):
32
+ raise NotImplementedError
33
+
34
+
35
+ class Use:
36
+ def __init__(self, injection: type[Injection]):
37
+ self.injection = injection
38
+
39
+ def __call__(self, *args, **kwargs):
40
+ def wrapper(func: Func | WrappedFunc) -> WrappedFunc:
41
+ wrapped_func = func if isinstance(func, WrappedFunc) else WrappedFunc(func)
42
+ wrapped_func.register(self.injection(*args, **kwargs))
43
+ return wrapped_func
44
+
45
+ return wrapper
46
+
47
+
48
+ class WrappedFunc:
49
+ def __init__(self, func: Func):
50
+ self.func = func
51
+ self.injections: list[Injection] = []
52
+
53
+ def register(self, injection: Injection):
54
+ self.injections.append(injection)
55
+
56
+ def __call__(self, **kwargs):
57
+ result = inject(self.func, **{
58
+ **kwargs,
59
+ **{injection.name: injection(**kwargs) for injection in self.injections}
60
+ })
61
+ return result if not inspect.isgenerator(result) else (yield from result)
62
+
63
+ def __repr__(self) -> str:
64
+ return f"<WrappedFunc {self.func.__name__}>"
65
+
66
+ __str__ = __repr__
67
+
68
+
69
+ __all__ = ["Use", "Injection", "WrappedFunc", "Func"]
@@ -0,0 +1,7 @@
1
+ from .base_stage import BaseStage
2
+ from .base_order import BaseOrder, Result
3
+ from .base_trader import BaseTrader
4
+
5
+ from .order import StockOrder
6
+ from .query import Query
7
+ from .portfolio import Portfolio
@@ -0,0 +1,45 @@
1
+ from typing import TypeVar, Generic, TYPE_CHECKING
2
+ from abc import ABC, abstractmethod
3
+
4
+ if TYPE_CHECKING:
5
+ from ..asset import BaseAsset
6
+
7
+ AssetType = TypeVar('AssetType', bound="BaseAsset")
8
+
9
+
10
+ class BaseOrder(Generic[AssetType], ABC):
11
+ def __init__(self, asset: AssetType, category: str, *args, **kwargs):
12
+ self.asset = asset
13
+ self.category = category
14
+
15
+ def type(self):
16
+ return self.__class__.__name__
17
+
18
+ @property
19
+ @abstractmethod
20
+ def extra(self):
21
+ raise NotImplementedError
22
+
23
+ @abstractmethod
24
+ def __repr__(self):
25
+ raise NotImplementedError
26
+
27
+ __str__ = __repr__
28
+
29
+
30
+ OrderType = TypeVar('OrderType', bound=BaseOrder)
31
+
32
+
33
+ class Result(Generic[OrderType]):
34
+ def __init__(self, *, order: OrderType, sold: list["BaseAsset"], brought: list["BaseAsset"]):
35
+ self.order = order
36
+ self.sold = sold
37
+ self.brought = brought
38
+
39
+ def __repr__(self):
40
+ return f"<Result sold={self.sold} brought={self.brought}>"
41
+
42
+ __str__ = __repr__
43
+
44
+
45
+ __all__ = ['BaseOrder', 'Result']
@@ -0,0 +1,16 @@
1
+ from enum import Flag
2
+ from datetime import time
3
+
4
+
5
+ class BaseStage(Flag):
6
+ @property
7
+ def time(self) -> time:
8
+ raise NotImplementedError
9
+
10
+ def __repr__(self):
11
+ return self.name
12
+
13
+ __str__ = __repr__
14
+
15
+
16
+ __all__ = ['BaseStage']