tradepose-models 1.1.0__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 (94) hide show
  1. tradepose_models/__init__.py +44 -0
  2. tradepose_models/auth/__init__.py +13 -0
  3. tradepose_models/auth/api_keys.py +52 -0
  4. tradepose_models/auth/auth.py +20 -0
  5. tradepose_models/base.py +57 -0
  6. tradepose_models/billing/__init__.py +33 -0
  7. tradepose_models/billing/checkout.py +17 -0
  8. tradepose_models/billing/plans.py +32 -0
  9. tradepose_models/billing/subscriptions.py +34 -0
  10. tradepose_models/billing/usage.py +71 -0
  11. tradepose_models/broker/__init__.py +34 -0
  12. tradepose_models/broker/account_config.py +93 -0
  13. tradepose_models/broker/account_models.py +61 -0
  14. tradepose_models/broker/binding.py +54 -0
  15. tradepose_models/broker/connection_status.py +14 -0
  16. tradepose_models/commands/__init__.py +8 -0
  17. tradepose_models/commands/trader_command.py +80 -0
  18. tradepose_models/datafeed/__init__.py +19 -0
  19. tradepose_models/datafeed/events.py +132 -0
  20. tradepose_models/enums/__init__.py +47 -0
  21. tradepose_models/enums/account_source.py +42 -0
  22. tradepose_models/enums/broker_type.py +21 -0
  23. tradepose_models/enums/currency.py +17 -0
  24. tradepose_models/enums/engagement_phase.py +47 -0
  25. tradepose_models/enums/execution_mode.py +16 -0
  26. tradepose_models/enums/export_type.py +23 -0
  27. tradepose_models/enums/freq.py +32 -0
  28. tradepose_models/enums/indicator_type.py +46 -0
  29. tradepose_models/enums/operation_type.py +19 -0
  30. tradepose_models/enums/order_strategy.py +47 -0
  31. tradepose_models/enums/orderbook_event_type.py +29 -0
  32. tradepose_models/enums/persist_mode.py +28 -0
  33. tradepose_models/enums/stream.py +14 -0
  34. tradepose_models/enums/task_status.py +23 -0
  35. tradepose_models/enums/trade_direction.py +42 -0
  36. tradepose_models/enums/trend_type.py +22 -0
  37. tradepose_models/enums/weekday.py +30 -0
  38. tradepose_models/enums.py +32 -0
  39. tradepose_models/events/__init__.py +11 -0
  40. tradepose_models/events/order_events.py +79 -0
  41. tradepose_models/export/__init__.py +19 -0
  42. tradepose_models/export/request.py +52 -0
  43. tradepose_models/export/requests.py +75 -0
  44. tradepose_models/export/task_metadata.py +97 -0
  45. tradepose_models/gateway/__init__.py +19 -0
  46. tradepose_models/gateway/responses.py +37 -0
  47. tradepose_models/indicators/__init__.py +56 -0
  48. tradepose_models/indicators/base.py +42 -0
  49. tradepose_models/indicators/factory.py +254 -0
  50. tradepose_models/indicators/market_profile.md +60 -0
  51. tradepose_models/indicators/market_profile.py +333 -0
  52. tradepose_models/indicators/market_profile_developer.md +1782 -0
  53. tradepose_models/indicators/market_profile_trading.md +1060 -0
  54. tradepose_models/indicators/momentum.py +53 -0
  55. tradepose_models/indicators/moving_average.py +63 -0
  56. tradepose_models/indicators/other.py +40 -0
  57. tradepose_models/indicators/trend.py +80 -0
  58. tradepose_models/indicators/volatility.py +57 -0
  59. tradepose_models/instruments/__init__.py +13 -0
  60. tradepose_models/instruments/instrument.py +87 -0
  61. tradepose_models/scheduler/__init__.py +9 -0
  62. tradepose_models/scheduler/results.py +49 -0
  63. tradepose_models/schemas/__init__.py +15 -0
  64. tradepose_models/schemas/enhanced_ohlcv.py +111 -0
  65. tradepose_models/schemas/performance.py +40 -0
  66. tradepose_models/schemas/trades.py +64 -0
  67. tradepose_models/schemas.py +34 -0
  68. tradepose_models/shared.py +15 -0
  69. tradepose_models/strategy/__init__.py +52 -0
  70. tradepose_models/strategy/base.py +56 -0
  71. tradepose_models/strategy/blueprint.py +55 -0
  72. tradepose_models/strategy/config.py +142 -0
  73. tradepose_models/strategy/entities.py +104 -0
  74. tradepose_models/strategy/helpers.py +173 -0
  75. tradepose_models/strategy/indicator_spec.py +531 -0
  76. tradepose_models/strategy/performance.py +66 -0
  77. tradepose_models/strategy/portfolio.py +171 -0
  78. tradepose_models/strategy/registry.py +249 -0
  79. tradepose_models/strategy/requests.py +33 -0
  80. tradepose_models/strategy/trigger.py +77 -0
  81. tradepose_models/trading/__init__.py +55 -0
  82. tradepose_models/trading/engagement.py +160 -0
  83. tradepose_models/trading/orderbook.py +73 -0
  84. tradepose_models/trading/orders.py +137 -0
  85. tradepose_models/trading/positions.py +78 -0
  86. tradepose_models/trading/trader_commands.py +138 -0
  87. tradepose_models/trading/trades_execution.py +27 -0
  88. tradepose_models/types.py +35 -0
  89. tradepose_models/utils/__init__.py +13 -0
  90. tradepose_models/utils/rate_converter.py +112 -0
  91. tradepose_models/validators.py +32 -0
  92. tradepose_models-1.1.0.dist-info/METADATA +633 -0
  93. tradepose_models-1.1.0.dist-info/RECORD +94 -0
  94. tradepose_models-1.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,173 @@
1
+ """
2
+ Helper Functions for Strategy Configuration
3
+
4
+ Provides convenient factory functions for creating IndicatorSpec, Trigger, and Blueprint instances.
5
+ """
6
+
7
+ from typing import Any, Dict, List, Optional, Union
8
+
9
+ import polars as pl
10
+
11
+ from ..enums import Freq, OrderStrategy, TradeDirection, TrendType
12
+ from .blueprint import Blueprint
13
+ from .indicator_spec import IndicatorSpec
14
+ from .trigger import Trigger
15
+
16
+
17
+ def create_indicator_spec(
18
+ freq: Union[Freq, str],
19
+ indicator: Dict[str, Any],
20
+ instrument: Optional[str] = None,
21
+ shift: int = 1,
22
+ ) -> IndicatorSpec:
23
+ """創建指標規範(簡化版工廠函數)
24
+
25
+ 使用 Indicator 靜態類創建 indicator dict,然後傳入此函數
26
+
27
+ Args:
28
+ freq: 頻率(使用 Freq enum 或字串)
29
+ indicator: 指標配置(使用 Indicator 靜態類創建)
30
+ instrument: 交易標的(顯示名稱,可選)
31
+ shift: 位移(預設 1)
32
+
33
+ Returns:
34
+ IndicatorSpec 實例,可直接調用 .col() 獲取 Polars 表達式
35
+
36
+ Examples:
37
+ >>> from tradepose_models import Freq, Indicator, create_indicator_spec
38
+ >>>
39
+ >>> # 方式 1: 使用 Freq enum + Indicator 靜態類
40
+ >>> sma_20 = create_indicator_spec(
41
+ ... freq=Freq.MIN_1,
42
+ ... indicator=Indicator.sma(period=20),
43
+ ... instrument="ES"
44
+ ... )
45
+ >>> print(sma_20.display_name()) # "ES_1min_SMA|20.close"
46
+ >>>
47
+ >>> # 方式 2: 使用字串(向後兼容)
48
+ >>> atr_14 = create_indicator_spec(
49
+ ... freq="1D",
50
+ ... indicator=Indicator.atr(period=14),
51
+ ... shift=2
52
+ ... )
53
+ >>> print(atr_14.display_name()) # "1D_ATR|14_s2"
54
+ >>>
55
+ >>> # 方式 3: SuperTrend
56
+ >>> st = create_indicator_spec(
57
+ ... freq=Freq.MIN_5,
58
+ ... indicator=Indicator.supertrend(multiplier=3.0, volatility_column="atr"),
59
+ ... instrument="BTC"
60
+ ... )
61
+ >>> print(st.display_name()) # "BTC_5min_ST|3.0x_atr"
62
+ >>>
63
+ >>> # 在策略中使用(最簡潔的寫法)
64
+ >>> sma_50 = create_indicator_spec(Freq.MIN_1, Indicator.sma(50), "ES")
65
+ >>> conditions = [
66
+ ... sma_20.col() > sma_50.col(),
67
+ ... pl.col("volume") > 1000
68
+ ... ]
69
+ """
70
+ return IndicatorSpec(
71
+ instrument=instrument,
72
+ instrument_id=None, # Will be populated by Gateway
73
+ freq=freq,
74
+ shift=shift,
75
+ indicator=indicator,
76
+ )
77
+
78
+
79
+ def create_trigger(
80
+ name: str,
81
+ conditions: List[pl.Expr],
82
+ price_expr: pl.Expr,
83
+ order_strategy: OrderStrategy = OrderStrategy.IMMEDIATE_ENTRY,
84
+ priority: int = 1,
85
+ note: Optional[str] = None,
86
+ ) -> Trigger:
87
+ """創建觸發器(用於開發時)
88
+
89
+ Args:
90
+ name: 觸發器名稱
91
+ conditions: 條件列表,可直接使用 pl.col() 等
92
+ price_expr: 價格表達式
93
+ order_strategy: 訂單策略(可使用 OrderStrategy enum 或字串,預設 OrderStrategy.IMMEDIATE_ENTRY)
94
+ priority: 優先級
95
+ note: 備註
96
+
97
+ Returns:
98
+ Trigger 實例
99
+
100
+ Example:
101
+ >>> # 使用 OrderStrategy enum(推薦)
102
+ >>> entry = create_trigger(
103
+ ... name="my_entry",
104
+ ... conditions=[
105
+ ... pl.col("sma_30") > pl.col("sma_50"),
106
+ ... pl.col("volume") > 1000
107
+ ... ],
108
+ ... price_expr=pl.col("open"),
109
+ ... order_strategy=OrderStrategy.IMMEDIATE_ENTRY
110
+ ... )
111
+ >>>
112
+ >>> # 或使用字串(向後兼容)
113
+ >>> entry = create_trigger(
114
+ ... name="my_entry",
115
+ ... conditions=[...],
116
+ ... price_expr=pl.col("open"),
117
+ ... order_strategy="ImmediateEntry"
118
+ ... )
119
+ >>>
120
+ >>> # 序列化為 JSON
121
+ >>> print(entry.model_dump_json())
122
+ """
123
+ return Trigger(
124
+ name=name,
125
+ conditions=conditions,
126
+ price_expr=price_expr,
127
+ order_strategy=order_strategy,
128
+ priority=priority,
129
+ note=note,
130
+ )
131
+
132
+
133
+ def create_blueprint(
134
+ name: str,
135
+ direction: TradeDirection,
136
+ entry_triggers: List[Trigger],
137
+ exit_triggers: List[Trigger],
138
+ trend_type: TrendType = TrendType.TREND,
139
+ entry_first: bool = True,
140
+ note: str = "",
141
+ ) -> Blueprint:
142
+ """創建藍圖(用於開發時)
143
+
144
+ Example:
145
+ >>> entry_trigger = create_trigger(
146
+ ... name="entry",
147
+ ... conditions=[pl.col("sma_30") > pl.col("sma_50")],
148
+ ... price_expr=pl.col("open")
149
+ ... )
150
+ >>>
151
+ >>> exit_trigger = create_trigger(
152
+ ... name="exit",
153
+ ... conditions=[pl.col("sma_30") < pl.col("sma_50")],
154
+ ... price_expr=pl.col("open"),
155
+ ... order_strategy="ImmediateExit"
156
+ ... )
157
+ >>>
158
+ >>> blueprint = create_blueprint(
159
+ ... name="my_strategy",
160
+ ... direction="Long",
161
+ ... entry_triggers=[entry_trigger],
162
+ ... exit_triggers=[exit_trigger]
163
+ ... )
164
+ """
165
+ return Blueprint(
166
+ name=name,
167
+ direction=direction,
168
+ trend_type=trend_type,
169
+ entry_first=entry_first,
170
+ note=note,
171
+ entry_triggers=entry_triggers,
172
+ exit_triggers=exit_triggers,
173
+ )
@@ -0,0 +1,531 @@
1
+ """
2
+ IndicatorSpec Model
3
+
4
+ Provides the IndicatorSpec class for specifying indicator configurations with frequency, shift, and instrument.
5
+ """
6
+
7
+ from typing import Annotated, Any, Optional, Union
8
+
9
+ import polars as pl
10
+ from pydantic import BaseModel, Field, field_validator
11
+
12
+ from ..enums import Freq
13
+ from ..indicators import (
14
+ ADXIndicator,
15
+ ATRIndicator,
16
+ ATRQuantileIndicator,
17
+ BollingerBandsIndicator,
18
+ CCIIndicator,
19
+ EMAIndicator,
20
+ MACDIndicator,
21
+ MarketProfileIndicator,
22
+ RawOhlcvIndicator,
23
+ RSIIndicator,
24
+ SMAIndicator,
25
+ SMMAIndicator,
26
+ StochasticIndicator,
27
+ SuperTrendIndicator,
28
+ WMAIndicator,
29
+ )
30
+
31
+ # ============================================================================
32
+ # Indicator Discriminated Union (强类型 Indicator 配置)
33
+ # ============================================================================
34
+
35
+ IndicatorConfig = Annotated[
36
+ Union[
37
+ # 移动平均类
38
+ SMAIndicator,
39
+ EMAIndicator,
40
+ SMMAIndicator,
41
+ WMAIndicator,
42
+ # 波动率类
43
+ ATRIndicator,
44
+ ATRQuantileIndicator,
45
+ # 趋势类
46
+ SuperTrendIndicator,
47
+ MACDIndicator,
48
+ ADXIndicator,
49
+ # 动量类
50
+ RSIIndicator,
51
+ CCIIndicator,
52
+ StochasticIndicator,
53
+ # 其他
54
+ BollingerBandsIndicator,
55
+ MarketProfileIndicator,
56
+ RawOhlcvIndicator,
57
+ ],
58
+ Field(discriminator="type"),
59
+ ]
60
+ """
61
+ 强类型 Indicator 配置
62
+
63
+ 使用 Pydantic discriminated union,根据 'type' 字段自动选择正确的模型:
64
+ - type="SMA" → SMAIndicator
65
+ - type="ATR" → ATRIndicator
66
+ - type="SuperTrend" → SuperTrendIndicator
67
+ - ... etc
68
+
69
+ 优点:
70
+ - 编译时类型检查
71
+ - IDE 自动补全
72
+ - 参数验证
73
+ - 自动 JSON 序列化/反序列化
74
+
75
+ Example:
76
+ >>> # 方式 1: 直接创建强类型模型
77
+ >>> atr = ATRIndicator(period=21)
78
+ >>>
79
+ >>> # 方式 2: 从 Dict 自动转换(API 兼容)
80
+ >>> indicator: IndicatorConfig = {"type": "ATR", "period": 21}
81
+ >>> # Pydantic 自动识别为 ATRIndicator
82
+ """
83
+
84
+
85
+ class IndicatorSpec(BaseModel):
86
+ """指標規範(强类型版本)"""
87
+
88
+ instrument: Optional[str] = Field(
89
+ None, description="交易標的(顯示名稱,可選,用於多商品場景)"
90
+ )
91
+ instrument_id: Optional[int] = Field(
92
+ None, description="交易標的 ID(資料庫查詢用,由 Gateway 填充)"
93
+ )
94
+ freq: Freq = Field(..., description="頻率 (Freq enum)")
95
+ shift: int = Field(1, description="位移(預設 1)")
96
+ indicator: IndicatorConfig = Field(..., description="指標配置(强类型 Pydantic 模型)")
97
+
98
+ @field_validator("freq", mode="before")
99
+ @classmethod
100
+ def convert_freq(cls, v: Any) -> Freq:
101
+ """自動轉換字串為 Freq enum(保持 API 兼容性)"""
102
+ if isinstance(v, str):
103
+ try:
104
+ return Freq(v)
105
+ except ValueError:
106
+ valid_values = [e.value for e in Freq]
107
+ raise ValueError(f"Invalid freq: '{v}'. Valid values: {', '.join(valid_values)}")
108
+ return v
109
+
110
+ @field_validator("indicator", mode="before")
111
+ @classmethod
112
+ def convert_indicator(cls, v: Any) -> IndicatorConfig:
113
+ """自動轉換 Dict 為強類型 Indicator 模型(保持 API 兼容性)
114
+
115
+ 接受:
116
+ - Dict[str, Any]: 從 API 返回或舊代碼(自動轉換)
117
+ - IndicatorConfig: 新代碼使用強類型模型
118
+
119
+ Pydantic 會根據 'type' 字段自動選擇正確的模型。
120
+ """
121
+ # Dict 會被 Pydantic 自動轉換為對應的 Indicator 模型
122
+ # 強類型模型直接返回
123
+ return v
124
+
125
+ @property
126
+ def short_name(self) -> str:
127
+ """生成指標簡短名稱(與 Rust 的 short_name 一致)
128
+
129
+ 格式範例:
130
+ - SMA: "SMA|20.close"
131
+ - EMA: "EMA|12.close"
132
+ - ATR: "ATR|14"
133
+ - SuperTrend: "ST|3.0x_atr"
134
+
135
+ Returns:
136
+ 指標簡稱字符串
137
+
138
+ Raises:
139
+ ValueError: 未知的指標類型
140
+ """
141
+ indicator_type = self.indicator.type
142
+
143
+ if indicator_type == "SMA":
144
+ return f"SMA|{self.indicator.period}.{self.indicator.column}"
145
+
146
+ elif indicator_type == "EMA":
147
+ return f"EMA|{self.indicator.period}.{self.indicator.column}"
148
+
149
+ elif indicator_type == "SMMA":
150
+ return f"SMMA|{self.indicator.period}.{self.indicator.column}"
151
+
152
+ elif indicator_type == "WMA":
153
+ return f"WMA|{self.indicator.period}.{self.indicator.column}"
154
+
155
+ elif indicator_type == "ATR":
156
+ # ATR 始終返回單一數值欄位,無 quantile
157
+ return f"ATR|{self.indicator.period}"
158
+
159
+ elif indicator_type == "AtrQuantile":
160
+ # 將 quantile 轉為百分比(例如 0.5 -> 50)
161
+ quantile_pct = int(self.indicator.quantile * 100)
162
+ # 格式:ATRQ|{atr_column}_Q{quantile%}_{window}
163
+ return f"ATRQ|{self.indicator.atr_column}_Q{quantile_pct}_{self.indicator.window}"
164
+
165
+ elif indicator_type == "SuperTrend":
166
+ return f"ST|{self.indicator.multiplier}x_{self.indicator.volatility_column}"
167
+
168
+ elif indicator_type == "MarketProfile":
169
+ # 提取 anchor_config 資訊
170
+ anchor_config = self.indicator.anchor_config
171
+ end_rule = anchor_config.get("end_rule", {})
172
+ lookback_days = anchor_config.get("lookback_days", 1)
173
+ tick_size = self.indicator.tick_size
174
+
175
+ # 格式化時間字串(支持新舊兩種格式)
176
+ rule_type = end_rule.get("type")
177
+
178
+ if rule_type == "DailyTime" or "DailyTime" in end_rule:
179
+ # 新格式: {"type": "DailyTime", "hour": 9, "minute": 15}
180
+ # 舊格式: {"DailyTime": {"hour": 9, "minute": 15}}
181
+ if rule_type == "DailyTime":
182
+ time_str = f"{end_rule['hour']:02d}{end_rule['minute']:02d}"
183
+ else:
184
+ daily = end_rule["DailyTime"]
185
+ time_str = f"{daily['hour']:02d}{daily['minute']:02d}"
186
+
187
+ elif rule_type == "WeeklyTime" or "WeeklyTime" in end_rule:
188
+ # 新格式: {"type": "WeeklyTime", "weekday": "Mon", "hour": 9, "minute": 15}
189
+ # 舊格式: {"WeeklyTime": {"weekday": 0, "hour": 9, "minute": 15}}
190
+ # 輸出格式: W{weekday_int}{HHMM} (與 Rust Server 一致)
191
+ str_to_int_map = {
192
+ "Mon": 0,
193
+ "Tue": 1,
194
+ "Wed": 2,
195
+ "Thu": 3,
196
+ "Fri": 4,
197
+ "Sat": 5,
198
+ "Sun": 6,
199
+ }
200
+ if rule_type == "WeeklyTime":
201
+ weekday = end_rule["weekday"]
202
+ # weekday 可能是字串 ("Mon") 或整數 (0)
203
+ if isinstance(weekday, str):
204
+ weekday_int = str_to_int_map.get(weekday, 0)
205
+ else:
206
+ weekday_int = weekday
207
+ time_str = f"W{weekday_int}{end_rule['hour']:02d}{end_rule['minute']:02d}"
208
+ else:
209
+ weekly = end_rule["WeeklyTime"]
210
+ weekday = weekly["weekday"]
211
+ if isinstance(weekday, str):
212
+ weekday_int = str_to_int_map.get(weekday, 0)
213
+ else:
214
+ weekday_int = weekday
215
+ time_str = f"W{weekday_int}{weekly['hour']:02d}{weekly['minute']:02d}"
216
+ else:
217
+ time_str = "UNKNOWN"
218
+
219
+ # 格式: MP|{time}_{lookback_days}_{tick_size}
220
+ # 注意:MarketProfile 不支持 indicator 層級的 shift
221
+ # TODO: 臨時方案 - 整數顯示為整數,非整數保留小數(與 Rust 行為一致)
222
+ # 詳見 docs/issues/tick-size-float-formatting-mismatch.md
223
+ tick_str = str(int(tick_size)) if tick_size == int(tick_size) else str(tick_size)
224
+ return f"MP|{time_str}_{lookback_days}_{tick_str}"
225
+
226
+ elif indicator_type == "CCI":
227
+ return f"CCI|{self.indicator.period}"
228
+
229
+ elif indicator_type == "RSI":
230
+ return f"RSI|{self.indicator.period}"
231
+
232
+ elif indicator_type == "BollingerBands":
233
+ return f"BB|{self.indicator.period}_{self.indicator.num_std}"
234
+
235
+ elif indicator_type == "MACD":
236
+ return f"MACD|{self.indicator.fast_period}_{self.indicator.slow_period}_{self.indicator.signal_period}"
237
+
238
+ elif indicator_type == "Stochastic":
239
+ return f"STOCH|{self.indicator.k_period}_{self.indicator.d_period}"
240
+
241
+ elif indicator_type == "ADX":
242
+ return f"ADX|{self.indicator.period}"
243
+
244
+ elif indicator_type == "RawOhlcv":
245
+ # RawOhlcv 只返回 column 名稱
246
+ return self.indicator.column
247
+
248
+ else:
249
+ raise ValueError(f"未知的指標類型: {indicator_type}")
250
+
251
+ @property
252
+ def display_name(self) -> str:
253
+ """生成完整的 column 名稱(與 Rust 的 display_name 一致)
254
+
255
+ 格式:
256
+ - 有 instrument_id: "{instrument_id}_{freq}_{indicator_short_name}[_s{shift}]"
257
+ - 無 instrument_id: "{freq}_{indicator_short_name}[_s{shift}]"
258
+
259
+ 範例:
260
+ - "ES_1min_SMA|20.close" (shift=1,不顯示)
261
+ - "1D_ATR|14_s2" (shift=2)
262
+ - "BTC_5min_EMA|12.close_s2" (shift=2)
263
+ - "1h_ST|3.0x_atr" (無 instrument_id)
264
+
265
+ Returns:
266
+ 完整的 column 名稱字符串
267
+ """
268
+ parts = []
269
+
270
+ # 1. instrument(如果有)
271
+ if self.instrument:
272
+ parts.append(self.instrument)
273
+
274
+ # 2. freq(處理 Freq enum)
275
+ freq_str = self.freq.value if isinstance(self.freq, Freq) else self.freq
276
+ parts.append(freq_str)
277
+
278
+ # 3. indicator short name
279
+ parts.append(self.short_name)
280
+
281
+ # 4. shift(只在非預設值時加入)
282
+ if self.shift != 1:
283
+ parts.append(f"s{self.shift}")
284
+
285
+ return "_".join(parts)
286
+
287
+ def col(self) -> pl.Expr:
288
+ """返回 Polars column expression(最常用的便捷方法)
289
+
290
+ Returns:
291
+ pl.col(display_name) 的 Polars 表達式
292
+
293
+ Example:
294
+ >>> spec = IndicatorSpec(
295
+ ... instrument_id="ES",
296
+ ... freq="1min",
297
+ ... shift=1,
298
+ ... indicator={"type": "SMA", "period": 20, "column": "close"}
299
+ ... )
300
+ >>> # 直接在條件中使用
301
+ >>> condition = spec.col() > 100
302
+ >>> # 或在過濾中使用
303
+ >>> df.filter(spec.col() > pl.col("open"))
304
+ """
305
+ return pl.col(self.display_name)
306
+
307
+ # ========================================================================
308
+ # Struct Field Accessors
309
+ # ========================================================================
310
+
311
+ @property
312
+ def market_profile(self) -> "MarketProfileAccessor":
313
+ """MarketProfile struct 欄位存取器"""
314
+ return MarketProfileAccessor(self)
315
+
316
+ @property
317
+ def supertrend(self) -> "SuperTrendAccessor":
318
+ """SuperTrend struct 欄位存取器"""
319
+ return SuperTrendAccessor(self)
320
+
321
+ @property
322
+ def macd_fields(self) -> "MACDAccessor":
323
+ """MACD struct 欄位存取器"""
324
+ return MACDAccessor(self)
325
+
326
+ @property
327
+ def adx_fields(self) -> "ADXAccessor":
328
+ """ADX struct 欄位存取器"""
329
+ return ADXAccessor(self)
330
+
331
+ @property
332
+ def stochastic(self) -> "StochasticAccessor":
333
+ """Stochastic struct 欄位存取器"""
334
+ return StochasticAccessor(self)
335
+
336
+ @property
337
+ def bollinger_bands(self) -> "BollingerBandsAccessor":
338
+ """BollingerBands struct 欄位存取器"""
339
+ return BollingerBandsAccessor(self)
340
+
341
+
342
+ # ============================================================================
343
+ # Struct Field Accessors
344
+ # ============================================================================
345
+
346
+
347
+ class StructFieldAccessor:
348
+ """Struct 欄位存取器基類"""
349
+
350
+ def __init__(self, spec: IndicatorSpec):
351
+ self._spec = spec
352
+
353
+ @property
354
+ def struct_col(self) -> pl.Expr:
355
+ """返回整個 struct 的 Polars 表達式"""
356
+ return self._spec.col()
357
+
358
+ def _field(self, name: str) -> pl.Expr:
359
+ """內部方法:取得 struct 子欄位"""
360
+ return self.struct_col.struct.field(name)
361
+
362
+
363
+ class MarketProfileAccessor(StructFieldAccessor):
364
+ """MarketProfile struct 欄位存取器
365
+
366
+ Example:
367
+ >>> mp = IndicatorSpec(freq=Freq.MIN_30, indicator=MarketProfileIndicator(...))
368
+ >>> mp.market_profile.poc # pl.col(...).struct.field("poc")
369
+ >>> mp.market_profile.vah # pl.col(...).struct.field("vah")
370
+ >>> mp.market_profile.profile_shape # pl.col(...).struct.field("profile_shape")
371
+ """
372
+
373
+ @property
374
+ def poc(self) -> pl.Expr:
375
+ """Point of Control"""
376
+ return self._field("poc")
377
+
378
+ @property
379
+ def vah(self) -> pl.Expr:
380
+ """Value Area High"""
381
+ return self._field("vah")
382
+
383
+ @property
384
+ def val(self) -> pl.Expr:
385
+ """Value Area Low"""
386
+ return self._field("val")
387
+
388
+ @property
389
+ def value_area(self) -> pl.Expr:
390
+ """Value Area (VAH - VAL)"""
391
+ return self._field("value_area")
392
+
393
+ @property
394
+ def segment_id(self) -> pl.Expr:
395
+ """Segment ID"""
396
+ return self._field("segment_id")
397
+
398
+ @property
399
+ def profile_shape(self) -> pl.Expr:
400
+ """Profile Shape (p_shape, b_shape, trend_day, normal, etc.)"""
401
+ return self._field("profile_shape")
402
+
403
+ @property
404
+ def tpo_distribution(self) -> pl.Expr:
405
+ """TPO Distribution"""
406
+ return self._field("tpo_distribution")
407
+
408
+
409
+ class SuperTrendAccessor(StructFieldAccessor):
410
+ """SuperTrend struct 欄位存取器
411
+
412
+ Example:
413
+ >>> st = IndicatorSpec(freq=Freq.MIN_30, indicator=SuperTrendIndicator(...))
414
+ >>> st.supertrend.direction # pl.col(...).struct.field("direction")
415
+ >>> st.supertrend.supertrend # pl.col(...).struct.field("supertrend")
416
+ """
417
+
418
+ @property
419
+ def direction(self) -> pl.Expr:
420
+ """Trend direction (1 = up, -1 = down)"""
421
+ return self._field("direction")
422
+
423
+ @property
424
+ def supertrend(self) -> pl.Expr:
425
+ """SuperTrend value"""
426
+ return self._field("supertrend")
427
+
428
+ @property
429
+ def long(self) -> pl.Expr:
430
+ """Long stop level"""
431
+ return self._field("long")
432
+
433
+ @property
434
+ def short(self) -> pl.Expr:
435
+ """Short stop level"""
436
+ return self._field("short")
437
+
438
+
439
+ class MACDAccessor(StructFieldAccessor):
440
+ """MACD struct 欄位存取器
441
+
442
+ Example:
443
+ >>> macd = IndicatorSpec(freq=Freq.MIN_30, indicator=MACDIndicator(...))
444
+ >>> macd.macd_fields.macd # pl.col(...).struct.field("macd")
445
+ >>> macd.macd_fields.histogram # pl.col(...).struct.field("histogram")
446
+ """
447
+
448
+ @property
449
+ def macd(self) -> pl.Expr:
450
+ """MACD line"""
451
+ return self._field("macd")
452
+
453
+ @property
454
+ def signal(self) -> pl.Expr:
455
+ """Signal line"""
456
+ return self._field("signal")
457
+
458
+ @property
459
+ def histogram(self) -> pl.Expr:
460
+ """MACD histogram"""
461
+ return self._field("histogram")
462
+
463
+
464
+ class ADXAccessor(StructFieldAccessor):
465
+ """ADX struct 欄位存取器
466
+
467
+ Example:
468
+ >>> adx = IndicatorSpec(freq=Freq.MIN_30, indicator=ADXIndicator(...))
469
+ >>> adx.adx_fields.adx # pl.col(...).struct.field("adx")
470
+ >>> adx.adx_fields.plus_di # pl.col(...).struct.field("plus_di")
471
+ """
472
+
473
+ @property
474
+ def adx(self) -> pl.Expr:
475
+ """ADX value"""
476
+ return self._field("adx")
477
+
478
+ @property
479
+ def plus_di(self) -> pl.Expr:
480
+ """+DI value"""
481
+ return self._field("plus_di")
482
+
483
+ @property
484
+ def minus_di(self) -> pl.Expr:
485
+ """-DI value"""
486
+ return self._field("minus_di")
487
+
488
+
489
+ class StochasticAccessor(StructFieldAccessor):
490
+ """Stochastic struct 欄位存取器
491
+
492
+ Example:
493
+ >>> stoch = IndicatorSpec(freq=Freq.MIN_30, indicator=StochasticIndicator(...))
494
+ >>> stoch.stochastic.k # pl.col(...).struct.field("k")
495
+ >>> stoch.stochastic.d # pl.col(...).struct.field("d")
496
+ """
497
+
498
+ @property
499
+ def k(self) -> pl.Expr:
500
+ """%K value"""
501
+ return self._field("k")
502
+
503
+ @property
504
+ def d(self) -> pl.Expr:
505
+ """%D value"""
506
+ return self._field("d")
507
+
508
+
509
+ class BollingerBandsAccessor(StructFieldAccessor):
510
+ """BollingerBands struct 欄位存取器
511
+
512
+ Example:
513
+ >>> bb = IndicatorSpec(freq=Freq.MIN_30, indicator=BollingerBandsIndicator(...))
514
+ >>> bb.bollinger_bands.upper # pl.col(...).struct.field("upper")
515
+ >>> bb.bollinger_bands.lower # pl.col(...).struct.field("lower")
516
+ """
517
+
518
+ @property
519
+ def upper(self) -> pl.Expr:
520
+ """Upper band"""
521
+ return self._field("upper")
522
+
523
+ @property
524
+ def middle(self) -> pl.Expr:
525
+ """Middle band (SMA)"""
526
+ return self._field("middle")
527
+
528
+ @property
529
+ def lower(self) -> pl.Expr:
530
+ """Lower band"""
531
+ return self._field("lower")