tradepose-client 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.
- tradepose_client/__init__.py +24 -4
- tradepose_client/builder/__init__.py +22 -0
- tradepose_client/builder/blueprint_builder.py +276 -0
- tradepose_client/builder/indicator_wrapper.py +126 -0
- tradepose_client/builder/strategy_builder.py +312 -0
- tradepose_client/builder/trading_context.py +162 -0
- tradepose_client/enums.py +176 -0
- tradepose_client/models.py +7 -73
- {tradepose_client-0.1.0.dist-info → tradepose_client-0.1.1.dist-info}/METADATA +1 -1
- tradepose_client-0.1.1.dist-info/RECORD +21 -0
- tradepose_client-0.1.0.dist-info/RECORD +0 -15
- {tradepose_client-0.1.0.dist-info → tradepose_client-0.1.1.dist-info}/WHEEL +0 -0
- {tradepose_client-0.1.0.dist-info → tradepose_client-0.1.1.dist-info}/licenses/LICENSE +0 -0
tradepose_client/__init__.py
CHANGED
|
@@ -19,14 +19,25 @@ from .models import (
|
|
|
19
19
|
Blueprint,
|
|
20
20
|
Trigger,
|
|
21
21
|
IndicatorSpec,
|
|
22
|
-
Freq,
|
|
23
|
-
OrderStrategy,
|
|
24
22
|
Indicator,
|
|
25
23
|
create_trigger,
|
|
26
24
|
create_blueprint,
|
|
27
25
|
create_indicator_spec,
|
|
28
26
|
parse_strategy,
|
|
29
27
|
)
|
|
28
|
+
from .enums import (
|
|
29
|
+
Freq,
|
|
30
|
+
OrderStrategy,
|
|
31
|
+
TradeDirection,
|
|
32
|
+
TrendType,
|
|
33
|
+
Weekday,
|
|
34
|
+
IndicatorType,
|
|
35
|
+
)
|
|
36
|
+
from .builder import (
|
|
37
|
+
TradingContext,
|
|
38
|
+
BlueprintBuilder,
|
|
39
|
+
StrategyBuilder,
|
|
40
|
+
)
|
|
30
41
|
from .schema import (
|
|
31
42
|
enhanced_ohlcv_schema,
|
|
32
43
|
trades_schema,
|
|
@@ -68,13 +79,22 @@ __all__ = [
|
|
|
68
79
|
"Blueprint",
|
|
69
80
|
"Trigger",
|
|
70
81
|
"IndicatorSpec",
|
|
71
|
-
"Freq",
|
|
72
|
-
"OrderStrategy",
|
|
73
82
|
"Indicator",
|
|
74
83
|
"create_trigger",
|
|
75
84
|
"create_blueprint",
|
|
76
85
|
"create_indicator_spec",
|
|
77
86
|
"parse_strategy",
|
|
87
|
+
# Enums
|
|
88
|
+
"Freq",
|
|
89
|
+
"OrderStrategy",
|
|
90
|
+
"TradeDirection",
|
|
91
|
+
"TrendType",
|
|
92
|
+
"Weekday",
|
|
93
|
+
"IndicatorType",
|
|
94
|
+
# Builder API (New)
|
|
95
|
+
"TradingContext",
|
|
96
|
+
"BlueprintBuilder",
|
|
97
|
+
"StrategyBuilder",
|
|
78
98
|
# Schema
|
|
79
99
|
"enhanced_ohlcv_schema",
|
|
80
100
|
"trades_schema",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Strategy Builder API
|
|
2
|
+
|
|
3
|
+
Provides a more concise and user-friendly strategy building interface.
|
|
4
|
+
|
|
5
|
+
Core classes:
|
|
6
|
+
- TradingContext: Trading Context fixed field accessor
|
|
7
|
+
- IndicatorSpecWrapper: Indicator wrapper (.col(), .display_name)
|
|
8
|
+
- BlueprintBuilder: Blueprint builder with chain calls
|
|
9
|
+
- StrategyBuilder: Strategy builder (main entry)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from .trading_context import TradingContext
|
|
13
|
+
from .indicator_wrapper import IndicatorSpecWrapper
|
|
14
|
+
from .blueprint_builder import BlueprintBuilder
|
|
15
|
+
from .strategy_builder import StrategyBuilder
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"TradingContext",
|
|
19
|
+
"IndicatorSpecWrapper",
|
|
20
|
+
"BlueprintBuilder",
|
|
21
|
+
"StrategyBuilder",
|
|
22
|
+
]
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Blueprint 链式构建器
|
|
3
|
+
|
|
4
|
+
支持链式添加 entry/exit triggers,最后通过 .build() 返回 BlueprintConfig。
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from tradepose_client.builder import BlueprintBuilder, TradingContext
|
|
8
|
+
import polars as pl
|
|
9
|
+
|
|
10
|
+
# 创建 Base Blueprint
|
|
11
|
+
base_bp = BlueprintBuilder(
|
|
12
|
+
name="base_trend",
|
|
13
|
+
direction="Long",
|
|
14
|
+
trend_type="Trend",
|
|
15
|
+
note="基础趋势策略"
|
|
16
|
+
).add_entry_trigger(
|
|
17
|
+
name="entry",
|
|
18
|
+
conditions=[pl.col("ema_20") > pl.col("ema_50")],
|
|
19
|
+
price_expr=pl.col("open"),
|
|
20
|
+
order_strategy="ImmediateEntry",
|
|
21
|
+
priority=1,
|
|
22
|
+
note="EMA 金叉"
|
|
23
|
+
).add_exit_trigger(
|
|
24
|
+
name="exit",
|
|
25
|
+
conditions=[pl.col("ema_20") < pl.col("ema_50")],
|
|
26
|
+
price_expr=pl.col("open"),
|
|
27
|
+
order_strategy="ImmediateExit",
|
|
28
|
+
priority=1,
|
|
29
|
+
note="EMA 死叉"
|
|
30
|
+
).build()
|
|
31
|
+
|
|
32
|
+
# 创建 Advanced Blueprint
|
|
33
|
+
adv_bp = BlueprintBuilder("risk_mgmt", "Long", "Trend")\
|
|
34
|
+
.add_exit_trigger(
|
|
35
|
+
name="stop_loss",
|
|
36
|
+
conditions=[],
|
|
37
|
+
price_expr=TradingContext.advanced_entry.entry_price - pl.col("atr") * 2,
|
|
38
|
+
order_strategy="StopLoss",
|
|
39
|
+
priority=1
|
|
40
|
+
)\
|
|
41
|
+
.add_exit_trigger(
|
|
42
|
+
name="take_profit",
|
|
43
|
+
conditions=[],
|
|
44
|
+
price_expr=TradingContext.advanced_entry.entry_price + pl.col("atr") * 3,
|
|
45
|
+
order_strategy="TakeProfit",
|
|
46
|
+
priority=2
|
|
47
|
+
)\
|
|
48
|
+
.build()
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
import polars as pl
|
|
52
|
+
from typing import List, Literal, Optional, Union, TYPE_CHECKING
|
|
53
|
+
|
|
54
|
+
if TYPE_CHECKING:
|
|
55
|
+
from tradepose_client.models import Blueprint, Trigger, OrderStrategy
|
|
56
|
+
from tradepose_client.enums import TradeDirection, TrendType
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class BlueprintBuilder:
|
|
60
|
+
"""
|
|
61
|
+
Blueprint 链式构建器
|
|
62
|
+
|
|
63
|
+
支持链式添加 entry/exit triggers,提供流畅的 API 体验。
|
|
64
|
+
|
|
65
|
+
Attributes:
|
|
66
|
+
name (str): Blueprint 名称
|
|
67
|
+
direction (str): 交易方向("Long", "Short", "Both")
|
|
68
|
+
trend_type (str): 趋势类型("Trend", "Range", "Reversal")
|
|
69
|
+
entry_first (bool): 是否必须先进场才能出场
|
|
70
|
+
note (str): 备注
|
|
71
|
+
|
|
72
|
+
Methods:
|
|
73
|
+
add_entry_trigger(...) -> BlueprintBuilder: 添加进场触发器(链式)
|
|
74
|
+
add_exit_trigger(...) -> BlueprintBuilder: 添加出场触发器(链式)
|
|
75
|
+
build() -> Blueprint: 构建最终 Blueprint 对象
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
def __init__(
|
|
79
|
+
self,
|
|
80
|
+
name: str,
|
|
81
|
+
direction: Union["TradeDirection", str],
|
|
82
|
+
trend_type: Union["TrendType", str] = "Trend",
|
|
83
|
+
entry_first: bool = True,
|
|
84
|
+
note: str = "",
|
|
85
|
+
):
|
|
86
|
+
"""
|
|
87
|
+
初始化 Blueprint 构建器
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
name: Blueprint 名称(唯一标识)
|
|
91
|
+
direction: 交易方向
|
|
92
|
+
- "Long": 做多
|
|
93
|
+
- "Short": 做空
|
|
94
|
+
- "Both": 双向(暂不支持)
|
|
95
|
+
trend_type: 趋势类型
|
|
96
|
+
- "Trend": 趋势跟随
|
|
97
|
+
- "Range": 区间震荡
|
|
98
|
+
- "Reversal": 反转交易
|
|
99
|
+
entry_first: 是否必须先进场才能出场(推荐 True)
|
|
100
|
+
note: Blueprint 说明
|
|
101
|
+
|
|
102
|
+
Examples:
|
|
103
|
+
>>> # Base Blueprint(简洁形式)
|
|
104
|
+
>>> bp = BlueprintBuilder("base", "Long", "Trend")
|
|
105
|
+
>>>
|
|
106
|
+
>>> # Advanced Blueprint(完整形式)
|
|
107
|
+
>>> adv_bp = BlueprintBuilder(
|
|
108
|
+
... name="risk_management",
|
|
109
|
+
... direction="Long",
|
|
110
|
+
... trend_type="Trend",
|
|
111
|
+
... entry_first=True,
|
|
112
|
+
... note="Stop Loss + Take Profit"
|
|
113
|
+
... )
|
|
114
|
+
"""
|
|
115
|
+
self.name = name
|
|
116
|
+
self.direction = direction
|
|
117
|
+
self.trend_type = trend_type
|
|
118
|
+
self.entry_first = entry_first
|
|
119
|
+
self.note = note
|
|
120
|
+
|
|
121
|
+
self._entry_triggers: List["Trigger"] = []
|
|
122
|
+
self._exit_triggers: List["Trigger"] = []
|
|
123
|
+
|
|
124
|
+
def add_entry_trigger(
|
|
125
|
+
self,
|
|
126
|
+
name: str,
|
|
127
|
+
conditions: List[pl.Expr],
|
|
128
|
+
price_expr: pl.Expr,
|
|
129
|
+
order_strategy: Union["OrderStrategy", str],
|
|
130
|
+
priority: int,
|
|
131
|
+
note: str = "",
|
|
132
|
+
) -> "BlueprintBuilder":
|
|
133
|
+
"""
|
|
134
|
+
添加进场触发器(链式调用)
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
name: 触发器名称(唯一标识)
|
|
138
|
+
conditions: 条件表达式列表(全部为 True 才触发)
|
|
139
|
+
price_expr: 价格表达式(Polars Expr)
|
|
140
|
+
order_strategy: 订单策略
|
|
141
|
+
- Base Blueprint 必须使用 "ImmediateEntry"
|
|
142
|
+
- Advanced Blueprint 可使用 "FavorableDelayEntry", "AdverseDelayEntry" 等
|
|
143
|
+
priority: 优先级(1-100,越小优先级越高)
|
|
144
|
+
note: 触发器说明
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
BlueprintBuilder: 返回自身,支持链式调用
|
|
148
|
+
|
|
149
|
+
Examples:
|
|
150
|
+
>>> bp = BlueprintBuilder("base", "Long", "Trend")\
|
|
151
|
+
... .add_entry_trigger(
|
|
152
|
+
... name="entry",
|
|
153
|
+
... conditions=[pl.col("ema_20") > pl.col("ema_50")],
|
|
154
|
+
... price_expr=pl.col("open"),
|
|
155
|
+
... order_strategy="ImmediateEntry",
|
|
156
|
+
... priority=1,
|
|
157
|
+
... note="EMA 金叉"
|
|
158
|
+
... )
|
|
159
|
+
"""
|
|
160
|
+
from tradepose_client.models import create_trigger
|
|
161
|
+
|
|
162
|
+
trigger = create_trigger(
|
|
163
|
+
name=name,
|
|
164
|
+
conditions=conditions,
|
|
165
|
+
price_expr=price_expr,
|
|
166
|
+
order_strategy=order_strategy,
|
|
167
|
+
priority=priority,
|
|
168
|
+
note=note,
|
|
169
|
+
)
|
|
170
|
+
self._entry_triggers.append(trigger)
|
|
171
|
+
return self
|
|
172
|
+
|
|
173
|
+
def add_exit_trigger(
|
|
174
|
+
self,
|
|
175
|
+
name: str,
|
|
176
|
+
conditions: List[pl.Expr],
|
|
177
|
+
price_expr: pl.Expr,
|
|
178
|
+
order_strategy: Union["OrderStrategy", str],
|
|
179
|
+
priority: int,
|
|
180
|
+
note: str = "",
|
|
181
|
+
) -> "BlueprintBuilder":
|
|
182
|
+
"""
|
|
183
|
+
添加出场触发器(链式调用)
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
name: 触发器名称(唯一标识)
|
|
187
|
+
conditions: 条件表达式列表(全部为 True 才触发)
|
|
188
|
+
price_expr: 价格表达式(Polars Expr)
|
|
189
|
+
order_strategy: 订单策略
|
|
190
|
+
- Base Blueprint 必须使用 "ImmediateExit"
|
|
191
|
+
- Advanced Blueprint 可使用 "StopLoss", "TakeProfit", "TrailingStop",
|
|
192
|
+
"Breakeven", "TimeoutExit" 等
|
|
193
|
+
priority: 优先级(1-100,越小优先级越高)
|
|
194
|
+
note: 触发器说明
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
BlueprintBuilder: 返回自身,支持链式调用
|
|
198
|
+
|
|
199
|
+
Examples:
|
|
200
|
+
>>> bp = BlueprintBuilder("risk_mgmt", "Long", "Trend")\
|
|
201
|
+
... .add_exit_trigger(
|
|
202
|
+
... name="stop_loss",
|
|
203
|
+
... conditions=[],
|
|
204
|
+
... price_expr=TradingContext.advanced_entry.entry_price - pl.col("atr") * 2,
|
|
205
|
+
... order_strategy="StopLoss",
|
|
206
|
+
... priority=1,
|
|
207
|
+
... note="固定止损 2 ATR"
|
|
208
|
+
... )\
|
|
209
|
+
... .add_exit_trigger(
|
|
210
|
+
... name="take_profit",
|
|
211
|
+
... conditions=[],
|
|
212
|
+
... price_expr=TradingContext.advanced_entry.entry_price + pl.col("atr") * 3,
|
|
213
|
+
... order_strategy="TakeProfit",
|
|
214
|
+
... priority=2,
|
|
215
|
+
... note="目标止盈 3 ATR"
|
|
216
|
+
... )
|
|
217
|
+
"""
|
|
218
|
+
from tradepose_client.models import create_trigger
|
|
219
|
+
|
|
220
|
+
trigger = create_trigger(
|
|
221
|
+
name=name,
|
|
222
|
+
conditions=conditions,
|
|
223
|
+
price_expr=price_expr,
|
|
224
|
+
order_strategy=order_strategy,
|
|
225
|
+
priority=priority,
|
|
226
|
+
note=note,
|
|
227
|
+
)
|
|
228
|
+
self._exit_triggers.append(trigger)
|
|
229
|
+
return self
|
|
230
|
+
|
|
231
|
+
def build(self) -> "Blueprint":
|
|
232
|
+
"""
|
|
233
|
+
构建最终 Blueprint 对象
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
Blueprint: 完整的 Blueprint 配置对象
|
|
237
|
+
|
|
238
|
+
Raises:
|
|
239
|
+
ValueError: 如果未添加任何 trigger
|
|
240
|
+
|
|
241
|
+
Examples:
|
|
242
|
+
>>> bp = BlueprintBuilder("base", "Long", "Trend")\
|
|
243
|
+
... .add_entry_trigger(...)\
|
|
244
|
+
... .add_exit_trigger(...)\
|
|
245
|
+
... .build()
|
|
246
|
+
>>>
|
|
247
|
+
>>> # 用于 StrategyBuilder
|
|
248
|
+
>>> builder.set_base_blueprint(bp)
|
|
249
|
+
>>> builder.add_advanced_blueprint(adv_bp)
|
|
250
|
+
"""
|
|
251
|
+
from tradepose_client.models import create_blueprint
|
|
252
|
+
|
|
253
|
+
if not self._entry_triggers and not self._exit_triggers:
|
|
254
|
+
raise ValueError(
|
|
255
|
+
f"Blueprint '{self.name}' must have at least one entry or exit trigger. "
|
|
256
|
+
f"Use .add_entry_trigger() or .add_exit_trigger() before calling .build()"
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
return create_blueprint(
|
|
260
|
+
name=self.name,
|
|
261
|
+
direction=self.direction,
|
|
262
|
+
entry_triggers=self._entry_triggers,
|
|
263
|
+
exit_triggers=self._exit_triggers,
|
|
264
|
+
trend_type=self.trend_type,
|
|
265
|
+
entry_first=self.entry_first,
|
|
266
|
+
note=self.note,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
def __repr__(self) -> str:
|
|
270
|
+
"""字符串表示"""
|
|
271
|
+
return (
|
|
272
|
+
f"BlueprintBuilder(name='{self.name}', "
|
|
273
|
+
f"direction='{self.direction}', "
|
|
274
|
+
f"entry_triggers={len(self._entry_triggers)}, "
|
|
275
|
+
f"exit_triggers={len(self._exit_triggers)})"
|
|
276
|
+
)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""
|
|
2
|
+
IndicatorSpec 包装器
|
|
3
|
+
|
|
4
|
+
提供更便捷的指标访问方式:
|
|
5
|
+
- .col() -> pl.Expr(用于条件表达式)
|
|
6
|
+
- .display_name -> str(用于依赖引用,作为属性访问)
|
|
7
|
+
- .spec -> IndicatorSpec(返回原始对象,用于最终 build)
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
from tradepose_client.builder import StrategyBuilder
|
|
11
|
+
|
|
12
|
+
builder = StrategyBuilder(...)
|
|
13
|
+
atr = builder.add_indicator("atr", period=21, freq="1D", shift=1)
|
|
14
|
+
|
|
15
|
+
# 使用 .col() 在条件表达式中
|
|
16
|
+
condition = atr.col() > 100
|
|
17
|
+
stop_loss_price = entry_price - atr.col() * 2
|
|
18
|
+
|
|
19
|
+
# 使用 .display_name 引用依赖(SuperTrend 引用 ATR)
|
|
20
|
+
st = builder.add_indicator(
|
|
21
|
+
"supertrend",
|
|
22
|
+
multiplier=3.0,
|
|
23
|
+
volatility_column=atr.display_name, # 属性访问
|
|
24
|
+
freq="1D",
|
|
25
|
+
shift=1
|
|
26
|
+
)
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
import polars as pl
|
|
30
|
+
from typing import TYPE_CHECKING
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from tradepose_client.models import IndicatorSpec
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class IndicatorSpecWrapper:
|
|
37
|
+
"""
|
|
38
|
+
IndicatorSpec 包装器
|
|
39
|
+
|
|
40
|
+
封装 IndicatorSpec,提供更便捷的访问方式。
|
|
41
|
+
|
|
42
|
+
Attributes:
|
|
43
|
+
display_name (str): 完整列名(属性访问)
|
|
44
|
+
spec (IndicatorSpec): 原始 IndicatorSpec 对象
|
|
45
|
+
|
|
46
|
+
Methods:
|
|
47
|
+
col() -> pl.Expr: 返回 Polars 表达式
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(self, spec: "IndicatorSpec"):
|
|
51
|
+
"""
|
|
52
|
+
初始化包装器
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
spec: IndicatorSpec 对象
|
|
56
|
+
"""
|
|
57
|
+
self._spec = spec
|
|
58
|
+
|
|
59
|
+
def col(self) -> pl.Expr:
|
|
60
|
+
"""
|
|
61
|
+
返回 Polars 表达式
|
|
62
|
+
|
|
63
|
+
用于条件表达式或价格计算。
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
pl.Expr: Polars 列表达式,等价于 pl.col(display_name)
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
>>> atr = builder.add_indicator("atr", period=21, freq="1D", shift=1)
|
|
70
|
+
>>>
|
|
71
|
+
>>> # 在条件中使用
|
|
72
|
+
>>> condition = atr.col() > 100
|
|
73
|
+
>>>
|
|
74
|
+
>>> # 在价格表达式中使用
|
|
75
|
+
>>> stop_loss_price = entry_price - atr.col() * 2
|
|
76
|
+
>>>
|
|
77
|
+
>>> # 访问 struct 字段(如 SuperTrend)
|
|
78
|
+
>>> st = builder.add_indicator("supertrend", ...)
|
|
79
|
+
>>> direction = st.col().struct.field("direction")
|
|
80
|
+
"""
|
|
81
|
+
return self._spec.col()
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def display_name(self) -> str:
|
|
85
|
+
"""
|
|
86
|
+
完整列名(属性访问)
|
|
87
|
+
|
|
88
|
+
用于指标依赖引用(如 SuperTrend 引用 ATR 的列名)。
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
str: 完整的列名,格式为 "{instrument_id}_{freq}_{indicator_short_name}"
|
|
92
|
+
|
|
93
|
+
Examples:
|
|
94
|
+
>>> atr = builder.add_indicator("atr", period=21, freq="1D", shift=1)
|
|
95
|
+
>>> print(atr.display_name)
|
|
96
|
+
"US100.cash_M15_FTMO_FUTURE_1D_ATR|21"
|
|
97
|
+
>>>
|
|
98
|
+
>>> # 用于依赖引用
|
|
99
|
+
>>> st = builder.add_indicator(
|
|
100
|
+
... "supertrend",
|
|
101
|
+
... multiplier=3.0,
|
|
102
|
+
... volatility_column=atr.display_name, # 引用 ATR 列名
|
|
103
|
+
... freq="1D",
|
|
104
|
+
... shift=1
|
|
105
|
+
... )
|
|
106
|
+
"""
|
|
107
|
+
return self._spec.display_name()
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def spec(self) -> "IndicatorSpec":
|
|
111
|
+
"""
|
|
112
|
+
返回原始 IndicatorSpec 对象
|
|
113
|
+
|
|
114
|
+
用于最终构建 StrategyConfig。
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
IndicatorSpec: 原始指标规范对象
|
|
118
|
+
|
|
119
|
+
Note:
|
|
120
|
+
用户通常不需要直接访问此属性,仅在高级场景下使用。
|
|
121
|
+
"""
|
|
122
|
+
return self._spec
|
|
123
|
+
|
|
124
|
+
def __repr__(self) -> str:
|
|
125
|
+
"""字符串表示"""
|
|
126
|
+
return f"IndicatorSpecWrapper(display_name='{self.display_name}')"
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
"""
|
|
2
|
+
策略构建器(主入口类)
|
|
3
|
+
|
|
4
|
+
管理整体策略构建流程:
|
|
5
|
+
1. 自动继承 base_instrument 和 base_freq
|
|
6
|
+
2. 添加指标(返回 IndicatorSpecWrapper)
|
|
7
|
+
3. 设置 base blueprint
|
|
8
|
+
4. 添加 advanced blueprints(链式)
|
|
9
|
+
5. 构建最终 StrategyConfig
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
from tradepose_client.builder import StrategyBuilder, BlueprintBuilder
|
|
13
|
+
|
|
14
|
+
# 1. 创建 builder
|
|
15
|
+
builder = StrategyBuilder(
|
|
16
|
+
name="KOG_US100_15T_ST_21_3",
|
|
17
|
+
base_instrument="US100.cash_M15_FTMO_FUTURE",
|
|
18
|
+
base_freq="15min"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# 2. 添加指标(自动继承 instrument_id)
|
|
22
|
+
atr = builder.add_indicator("atr", period=21, freq="1D", shift=1)
|
|
23
|
+
st = builder.add_indicator(
|
|
24
|
+
"supertrend",
|
|
25
|
+
multiplier=3.0,
|
|
26
|
+
volatility_column=atr.display_name,
|
|
27
|
+
freq="1D",
|
|
28
|
+
shift=1
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# 3. 创建并设置 base blueprint
|
|
32
|
+
base_bp = BlueprintBuilder("base", "Long", "Trend")\
|
|
33
|
+
.add_entry_trigger(...)\
|
|
34
|
+
.add_exit_trigger(...)\
|
|
35
|
+
.build()
|
|
36
|
+
|
|
37
|
+
builder.set_base_blueprint(base_bp)
|
|
38
|
+
|
|
39
|
+
# 4. 添加 advanced blueprints
|
|
40
|
+
adv_bp = BlueprintBuilder("risk_mgmt", "Long", "Trend")\
|
|
41
|
+
.add_exit_trigger(...)\
|
|
42
|
+
.build()
|
|
43
|
+
|
|
44
|
+
builder.add_advanced_blueprint(adv_bp)
|
|
45
|
+
|
|
46
|
+
# 5. 构建最终策略
|
|
47
|
+
strategy = builder.build(
|
|
48
|
+
volatility_indicator=atr,
|
|
49
|
+
note="US100 顺势策略"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# 6. 保存或注册
|
|
53
|
+
strategy.save("strategy.json")
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
from typing import List, Optional, Union, TYPE_CHECKING
|
|
57
|
+
|
|
58
|
+
if TYPE_CHECKING:
|
|
59
|
+
from tradepose_client.models import StrategyConfig, Blueprint, Freq
|
|
60
|
+
from tradepose_client.enums import IndicatorType
|
|
61
|
+
|
|
62
|
+
from .indicator_wrapper import IndicatorSpecWrapper
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class StrategyBuilder:
|
|
66
|
+
"""
|
|
67
|
+
策略构建器(主入口类)
|
|
68
|
+
|
|
69
|
+
管理整体策略构建流程,自动继承 base_instrument 和 base_freq。
|
|
70
|
+
|
|
71
|
+
Attributes:
|
|
72
|
+
name (str): 策略名称
|
|
73
|
+
base_instrument (str): 基准商品
|
|
74
|
+
base_freq (Freq): 基准频率
|
|
75
|
+
|
|
76
|
+
Methods:
|
|
77
|
+
add_indicator(indicator_type, **kwargs) -> IndicatorSpecWrapper:
|
|
78
|
+
添加指标(自动继承 instrument_id)
|
|
79
|
+
set_base_blueprint(blueprint) -> StrategyBuilder:
|
|
80
|
+
设置 Base Blueprint
|
|
81
|
+
add_advanced_blueprint(blueprint) -> StrategyBuilder:
|
|
82
|
+
添加 Advanced Blueprint(链式)
|
|
83
|
+
build(volatility_indicator, note) -> StrategyConfig:
|
|
84
|
+
构建最终 StrategyConfig
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def __init__(
|
|
88
|
+
self,
|
|
89
|
+
name: str,
|
|
90
|
+
base_instrument: str,
|
|
91
|
+
base_freq: str,
|
|
92
|
+
):
|
|
93
|
+
"""
|
|
94
|
+
初始化策略构建器
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
name: 策略名称(唯一标识)
|
|
98
|
+
base_instrument: 基准商品 ID(所有指标自动继承此值)
|
|
99
|
+
base_freq: 基准频率(支持字符串,如 "15min", "1D")
|
|
100
|
+
|
|
101
|
+
Examples:
|
|
102
|
+
>>> builder = StrategyBuilder(
|
|
103
|
+
... name="KOG_US100_15T_ST_21_3",
|
|
104
|
+
... base_instrument="US100.cash_M15_FTMO_FUTURE",
|
|
105
|
+
... base_freq="15min"
|
|
106
|
+
... )
|
|
107
|
+
"""
|
|
108
|
+
self.name = name
|
|
109
|
+
self.base_instrument = base_instrument
|
|
110
|
+
self.base_freq = base_freq # 字符串形式,稍后转换
|
|
111
|
+
|
|
112
|
+
self._indicators: List[IndicatorSpecWrapper] = []
|
|
113
|
+
self._base_blueprint: Optional["Blueprint"] = None
|
|
114
|
+
self._advanced_blueprints: List["Blueprint"] = []
|
|
115
|
+
|
|
116
|
+
def add_indicator(
|
|
117
|
+
self,
|
|
118
|
+
indicator_type: Union["IndicatorType", str],
|
|
119
|
+
freq: Union["Freq", str],
|
|
120
|
+
shift: int = 1,
|
|
121
|
+
instrument_id: Optional[str] = None,
|
|
122
|
+
**kwargs,
|
|
123
|
+
) -> IndicatorSpecWrapper:
|
|
124
|
+
"""
|
|
125
|
+
添加指标(支持可选 instrument_id 覆盖)
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
indicator_type: 指标类型(支持 IndicatorType enum 或字符串)
|
|
129
|
+
- IndicatorType.ATR 或 "atr"
|
|
130
|
+
- IndicatorType.SMA 或 "sma"
|
|
131
|
+
- IndicatorType.SUPERTREND 或 "supertrend"
|
|
132
|
+
freq: 指标频率(支持 Freq enum 或字符串)
|
|
133
|
+
- Freq.DAY_1 或 "1D"
|
|
134
|
+
- Freq.HOUR_1 或 "1h"
|
|
135
|
+
- Freq.MIN_15 或 "15min"
|
|
136
|
+
shift: 位移(默认 1,依赖指标通常使用 0)
|
|
137
|
+
instrument_id: 商品 ID(默认 None,使用 base_instrument)
|
|
138
|
+
- None: 使用 self.base_instrument(常见用法)
|
|
139
|
+
- "OTHER_INSTRUMENT": 使用其他商品(跨商品引用)
|
|
140
|
+
**kwargs: 指标参数(传递给 Indicator 工厂方法)
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
IndicatorSpecWrapper: 指标包装器,提供 .col() 和 .display_name
|
|
144
|
+
|
|
145
|
+
Examples:
|
|
146
|
+
>>> # 使用 enum(推荐,类型安全)
|
|
147
|
+
>>> atr = builder.add_indicator(
|
|
148
|
+
... IndicatorType.ATR,
|
|
149
|
+
... period=21,
|
|
150
|
+
... freq=Freq.DAY_1,
|
|
151
|
+
... shift=1
|
|
152
|
+
... )
|
|
153
|
+
>>>
|
|
154
|
+
>>> # 使用字符串(向后兼容)
|
|
155
|
+
>>> atr = builder.add_indicator("atr", period=21, freq="1D", shift=1)
|
|
156
|
+
>>>
|
|
157
|
+
>>> # 跨商品引用(使用其他商品的指标)
|
|
158
|
+
>>> vix_atr = builder.add_indicator(
|
|
159
|
+
... IndicatorType.ATR,
|
|
160
|
+
... period=21,
|
|
161
|
+
... freq=Freq.DAY_1,
|
|
162
|
+
... shift=1,
|
|
163
|
+
... instrument_id="VIX.cash" # 引用 VIX 的 ATR
|
|
164
|
+
... )
|
|
165
|
+
>>>
|
|
166
|
+
>>> # 依赖指标(SuperTrend 引用 ATR)
|
|
167
|
+
>>> st = builder.add_indicator(
|
|
168
|
+
... IndicatorType.SUPERTREND,
|
|
169
|
+
... multiplier=3.0,
|
|
170
|
+
... volatility_column=atr.display_name, # 引用依赖
|
|
171
|
+
... freq=Freq.DAY_1,
|
|
172
|
+
... shift=1
|
|
173
|
+
... )
|
|
174
|
+
"""
|
|
175
|
+
from tradepose_client.models import Indicator, create_indicator_spec, Freq
|
|
176
|
+
from tradepose_client.enums import IndicatorType
|
|
177
|
+
|
|
178
|
+
# 转换 indicator_type 为字符串
|
|
179
|
+
if isinstance(indicator_type, IndicatorType):
|
|
180
|
+
indicator_type_str = indicator_type.value
|
|
181
|
+
else:
|
|
182
|
+
indicator_type_str = indicator_type
|
|
183
|
+
|
|
184
|
+
# 动态调用 Indicator 工厂方法
|
|
185
|
+
if not hasattr(Indicator, indicator_type_str):
|
|
186
|
+
raise ValueError(
|
|
187
|
+
f"Unknown indicator type: '{indicator_type_str}'. "
|
|
188
|
+
f"Available: {', '.join([e.value for e in IndicatorType])}"
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
indicator_factory = getattr(Indicator, indicator_type_str)
|
|
192
|
+
indicator_config = indicator_factory(**kwargs)
|
|
193
|
+
|
|
194
|
+
# 转换 freq 字符串/enum 为 Freq enum
|
|
195
|
+
freq_enum = Freq(freq) if isinstance(freq, str) else freq
|
|
196
|
+
|
|
197
|
+
# 使用 instrument_id(如果提供),否则使用 base_instrument
|
|
198
|
+
final_instrument_id = instrument_id if instrument_id is not None else self.base_instrument
|
|
199
|
+
|
|
200
|
+
# 创建 IndicatorSpec
|
|
201
|
+
spec = create_indicator_spec(
|
|
202
|
+
freq=freq_enum,
|
|
203
|
+
indicator=indicator_config,
|
|
204
|
+
instrument_id=final_instrument_id,
|
|
205
|
+
shift=shift,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
wrapper = IndicatorSpecWrapper(spec)
|
|
209
|
+
self._indicators.append(wrapper)
|
|
210
|
+
return wrapper
|
|
211
|
+
|
|
212
|
+
def set_base_blueprint(self, blueprint: "Blueprint") -> "StrategyBuilder":
|
|
213
|
+
"""
|
|
214
|
+
设置 Base Blueprint
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
blueprint: Base Blueprint 对象(通常由 BlueprintBuilder 创建)
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
StrategyBuilder: 返回自身,支持链式调用
|
|
221
|
+
|
|
222
|
+
Examples:
|
|
223
|
+
>>> base_bp = BlueprintBuilder("base", "Long", "Trend")\
|
|
224
|
+
... .add_entry_trigger(...)\
|
|
225
|
+
... .add_exit_trigger(...)\
|
|
226
|
+
... .build()
|
|
227
|
+
>>>
|
|
228
|
+
>>> builder.set_base_blueprint(base_bp)
|
|
229
|
+
"""
|
|
230
|
+
self._base_blueprint = blueprint
|
|
231
|
+
return self
|
|
232
|
+
|
|
233
|
+
def add_advanced_blueprint(self, blueprint: "Blueprint") -> "StrategyBuilder":
|
|
234
|
+
"""
|
|
235
|
+
添加 Advanced Blueprint(链式调用)
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
blueprint: Advanced Blueprint 对象(通常由 BlueprintBuilder 创建)
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
StrategyBuilder: 返回自身,支持链式调用
|
|
242
|
+
|
|
243
|
+
Examples:
|
|
244
|
+
>>> adv_bp = BlueprintBuilder("risk_mgmt", "Long", "Trend")\
|
|
245
|
+
... .add_exit_trigger(...)\
|
|
246
|
+
... .build()
|
|
247
|
+
>>>
|
|
248
|
+
>>> builder.add_advanced_blueprint(adv_bp)
|
|
249
|
+
"""
|
|
250
|
+
self._advanced_blueprints.append(blueprint)
|
|
251
|
+
return self
|
|
252
|
+
|
|
253
|
+
def build(
|
|
254
|
+
self,
|
|
255
|
+
volatility_indicator: IndicatorSpecWrapper,
|
|
256
|
+
note: str = "",
|
|
257
|
+
) -> "StrategyConfig":
|
|
258
|
+
"""
|
|
259
|
+
构建最终 StrategyConfig
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
volatility_indicator: 波动率指标(通常是 ATR)
|
|
263
|
+
note: 策略说明
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
StrategyConfig: 完整的策略配置对象
|
|
267
|
+
|
|
268
|
+
Raises:
|
|
269
|
+
ValueError: 如果未设置 base_blueprint
|
|
270
|
+
|
|
271
|
+
Examples:
|
|
272
|
+
>>> strategy = builder.build(
|
|
273
|
+
... volatility_indicator=atr,
|
|
274
|
+
... note="US100 顺势策略 - SuperTrend(21,3)"
|
|
275
|
+
... )
|
|
276
|
+
>>>
|
|
277
|
+
>>> # 保存为 JSON
|
|
278
|
+
>>> strategy.save("strategy.json")
|
|
279
|
+
>>>
|
|
280
|
+
>>> # 或注册到 API
|
|
281
|
+
>>> client.register_strategy(strategy.to_json())
|
|
282
|
+
"""
|
|
283
|
+
from tradepose_client.models import StrategyConfig, Freq
|
|
284
|
+
|
|
285
|
+
if not self._base_blueprint:
|
|
286
|
+
raise ValueError(
|
|
287
|
+
"Base blueprint is required. Use .set_base_blueprint() first."
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
# 转换 base_freq 为 Freq enum
|
|
291
|
+
base_freq_enum = Freq(self.base_freq) if isinstance(self.base_freq, str) else self.base_freq
|
|
292
|
+
|
|
293
|
+
return StrategyConfig(
|
|
294
|
+
name=self.name,
|
|
295
|
+
base_instrument=self.base_instrument,
|
|
296
|
+
base_freq=base_freq_enum,
|
|
297
|
+
volatility_indicator=volatility_indicator.spec,
|
|
298
|
+
indicators=[ind.spec for ind in self._indicators],
|
|
299
|
+
base_blueprint=self._base_blueprint,
|
|
300
|
+
advanced_blueprints=self._advanced_blueprints,
|
|
301
|
+
note=note,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
def __repr__(self) -> str:
|
|
305
|
+
"""字符串表示"""
|
|
306
|
+
return (
|
|
307
|
+
f"StrategyBuilder(name='{self.name}', "
|
|
308
|
+
f"base_instrument='{self.base_instrument}', "
|
|
309
|
+
f"base_freq='{self.base_freq}', "
|
|
310
|
+
f"indicators={len(self._indicators)}, "
|
|
311
|
+
f"advanced_blueprints={len(self._advanced_blueprints)})"
|
|
312
|
+
)
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Trading Context 固定字段访问器
|
|
3
|
+
|
|
4
|
+
基于 schema.py 中定义的 struct 字段,提供简洁的属性访问方式,
|
|
5
|
+
避免繁琐的 `.struct.field()` 调用。
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
from tradepose_client.builder import TradingContext
|
|
9
|
+
import polars as pl
|
|
10
|
+
|
|
11
|
+
# 简洁访问(返回 pl.Expr)
|
|
12
|
+
entry_price = TradingContext.base.entry_price
|
|
13
|
+
highest = TradingContext.advanced_entry.highest_since_entry
|
|
14
|
+
bars = TradingContext.advanced_exit.bars_since_entry
|
|
15
|
+
|
|
16
|
+
# 用于策略条件表达式
|
|
17
|
+
condition = TradingContext.base.bars_in_position > 50
|
|
18
|
+
stop_loss_price = TradingContext.advanced_entry.entry_price - pl.col("atr") * 2
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import polars as pl
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TradingContextProxy:
|
|
25
|
+
"""
|
|
26
|
+
Trading Context 字段访问代理
|
|
27
|
+
|
|
28
|
+
为 base_trading_context, advanced_entry_trading_context,
|
|
29
|
+
advanced_exit_trading_context 提供统一的属性访问接口。
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
context_name: 上下文字段名称(如 "base_trading_context")
|
|
33
|
+
context_type: 上下文类型("base" 或 "advanced")
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, context_name: str, context_type: str):
|
|
37
|
+
self._context_name = context_name
|
|
38
|
+
self._context_type = context_type
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def entry_price(self) -> pl.Expr:
|
|
42
|
+
"""
|
|
43
|
+
进场价格
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
pl.Expr: Polars 表达式,可直接用于条件或价格计算
|
|
47
|
+
"""
|
|
48
|
+
return pl.col(self._context_name).struct.field("position_entry_price")
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def bars_in_position(self) -> pl.Expr:
|
|
52
|
+
"""
|
|
53
|
+
持仓 K 线数(仅适用于 base_trading_context)
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
pl.Expr: Polars 表达式
|
|
57
|
+
|
|
58
|
+
Note:
|
|
59
|
+
- base_trading_context 使用 "bars_in_position"
|
|
60
|
+
- advanced 使用 "bars_since_advanced_entry"(请用 .bars_since_entry)
|
|
61
|
+
"""
|
|
62
|
+
if self._context_type != "base":
|
|
63
|
+
raise AttributeError(
|
|
64
|
+
f"'bars_in_position' only available for base context. "
|
|
65
|
+
f"Use '.bars_since_entry' for advanced contexts."
|
|
66
|
+
)
|
|
67
|
+
return pl.col(self._context_name).struct.field("bars_in_position")
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def bars_since_entry(self) -> pl.Expr:
|
|
71
|
+
"""
|
|
72
|
+
进场后 K 线数(仅适用于 advanced contexts)
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
pl.Expr: Polars 表达式
|
|
76
|
+
|
|
77
|
+
Note:
|
|
78
|
+
- advanced_entry/exit_trading_context 使用 "bars_since_advanced_entry"
|
|
79
|
+
- base 使用 "bars_in_position"(请用 .bars_in_position)
|
|
80
|
+
"""
|
|
81
|
+
if self._context_type == "base":
|
|
82
|
+
raise AttributeError(
|
|
83
|
+
f"'bars_since_entry' not available for base context. "
|
|
84
|
+
f"Use '.bars_in_position' for base context."
|
|
85
|
+
)
|
|
86
|
+
return pl.col(self._context_name).struct.field("bars_since_advanced_entry")
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def highest_since_entry(self) -> pl.Expr:
|
|
90
|
+
"""
|
|
91
|
+
进场以来最高价
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
pl.Expr: Polars 表达式,可用于 trailing stop 计算
|
|
95
|
+
"""
|
|
96
|
+
return pl.col(self._context_name).struct.field("highest_since_entry")
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def lowest_since_entry(self) -> pl.Expr:
|
|
100
|
+
"""
|
|
101
|
+
进场以来最低价
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
pl.Expr: Polars 表达式,可用于 short position trailing stop 计算
|
|
105
|
+
"""
|
|
106
|
+
return pl.col(self._context_name).struct.field("lowest_since_entry")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class TradingContext:
|
|
110
|
+
"""
|
|
111
|
+
Trading Context 统一访问器
|
|
112
|
+
|
|
113
|
+
提供三种 trading context 的属性访问:
|
|
114
|
+
- base: base_trading_context
|
|
115
|
+
- advanced_entry: advanced_entry_trading_context
|
|
116
|
+
- advanced_exit: advanced_exit_trading_context
|
|
117
|
+
|
|
118
|
+
Usage:
|
|
119
|
+
# Base context(Base Blueprint 生成)
|
|
120
|
+
TradingContext.base.entry_price
|
|
121
|
+
TradingContext.base.bars_in_position
|
|
122
|
+
TradingContext.base.highest_since_entry
|
|
123
|
+
TradingContext.base.lowest_since_entry
|
|
124
|
+
|
|
125
|
+
# Advanced Entry context(Advanced Entry Triggers 使用)
|
|
126
|
+
TradingContext.advanced_entry.entry_price
|
|
127
|
+
TradingContext.advanced_entry.bars_since_entry
|
|
128
|
+
TradingContext.advanced_entry.highest_since_entry
|
|
129
|
+
TradingContext.advanced_entry.lowest_since_entry
|
|
130
|
+
|
|
131
|
+
# Advanced Exit context(Advanced Exit Triggers 使用)
|
|
132
|
+
TradingContext.advanced_exit.entry_price
|
|
133
|
+
TradingContext.advanced_exit.bars_since_entry
|
|
134
|
+
TradingContext.advanced_exit.highest_since_entry
|
|
135
|
+
TradingContext.advanced_exit.lowest_since_entry
|
|
136
|
+
|
|
137
|
+
Examples:
|
|
138
|
+
# Stop Loss(Long)
|
|
139
|
+
stop_loss_price = (
|
|
140
|
+
TradingContext.advanced_entry.entry_price -
|
|
141
|
+
pl.col("atr") * 2
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Trailing Stop(Long)
|
|
145
|
+
trailing_stop_price = (
|
|
146
|
+
TradingContext.advanced_entry.highest_since_entry -
|
|
147
|
+
pl.col("atr") * 2
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# 持倉時間過濾
|
|
151
|
+
timeout_condition = TradingContext.advanced_entry.bars_since_entry > 100
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
base = TradingContextProxy("base_trading_context", "base")
|
|
155
|
+
advanced_entry = TradingContextProxy("advanced_entry_trading_context", "advanced")
|
|
156
|
+
advanced_exit = TradingContextProxy("advanced_exit_trading_context", "advanced")
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# 向后兼容的别名
|
|
160
|
+
BaseContext = TradingContext.base
|
|
161
|
+
AdvancedEntryContext = TradingContext.advanced_entry
|
|
162
|
+
AdvancedExitContext = TradingContext.advanced_exit
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Enumerations for Tradepose strategy configuration
|
|
3
|
+
|
|
4
|
+
All enums are aligned with Rust backend types for JSON serialization.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Freq(str, Enum):
|
|
11
|
+
"""
|
|
12
|
+
Time frequency enum (aligned with Rust Freq enum)
|
|
13
|
+
|
|
14
|
+
Values:
|
|
15
|
+
MIN_1: 1 minute
|
|
16
|
+
MIN_5: 5 minutes
|
|
17
|
+
MIN_15: 15 minutes
|
|
18
|
+
MIN_30: 30 minutes
|
|
19
|
+
HOUR_1: 1 hour
|
|
20
|
+
HOUR_4: 4 hours
|
|
21
|
+
DAY_1: 1 day
|
|
22
|
+
WEEK_1: 1 week
|
|
23
|
+
MONTH_1: 1 month
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
MIN_1 = "1min"
|
|
27
|
+
MIN_5 = "5min"
|
|
28
|
+
MIN_15 = "15min"
|
|
29
|
+
MIN_30 = "30min"
|
|
30
|
+
HOUR_1 = "1h"
|
|
31
|
+
HOUR_4 = "4h"
|
|
32
|
+
DAY_1 = "1D"
|
|
33
|
+
WEEK_1 = "1W"
|
|
34
|
+
MONTH_1 = "1M"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class OrderStrategy(str, Enum):
|
|
38
|
+
"""
|
|
39
|
+
Order strategy enum (aligned with Rust OrderStrategy enum)
|
|
40
|
+
|
|
41
|
+
Used to specify the execution strategy for entry/exit triggers.
|
|
42
|
+
|
|
43
|
+
Rust mapping:
|
|
44
|
+
- Rust: OrderStrategy::ImmediateEntry → Python: OrderStrategy.IMMEDIATE_ENTRY (u32: 0)
|
|
45
|
+
- Rust: OrderStrategy::FavorableDelayEntry → Python: OrderStrategy.FAVORABLE_DELAY_ENTRY (u32: 1)
|
|
46
|
+
- Rust: OrderStrategy::AdverseDelayEntry → Python: OrderStrategy.ADVERSE_DELAY_ENTRY (u32: 2)
|
|
47
|
+
- Rust: OrderStrategy::ImmediateExit → Python: OrderStrategy.IMMEDIATE_EXIT (u32: 3)
|
|
48
|
+
- Rust: OrderStrategy::StopLoss → Python: OrderStrategy.STOP_LOSS (u32: 4)
|
|
49
|
+
- Rust: OrderStrategy::TakeProfit → Python: OrderStrategy.TAKE_PROFIT (u32: 5)
|
|
50
|
+
- Rust: OrderStrategy::TrailingStop → Python: OrderStrategy.TRAILING_STOP (u32: 6)
|
|
51
|
+
- Rust: OrderStrategy::Breakeven → Python: OrderStrategy.BREAKEVEN (u32: 7)
|
|
52
|
+
- Rust: OrderStrategy::TimeoutExit → Python: OrderStrategy.TIMEOUT_EXIT (u32: 8)
|
|
53
|
+
|
|
54
|
+
Entry Strategies:
|
|
55
|
+
IMMEDIATE_ENTRY: Immediate entry on signal (required for Base Blueprint)
|
|
56
|
+
FAVORABLE_DELAY_ENTRY: Wait for favorable price (pullback/retracement)
|
|
57
|
+
ADVERSE_DELAY_ENTRY: Wait for breakout/aggressive entry
|
|
58
|
+
|
|
59
|
+
Exit Strategies:
|
|
60
|
+
IMMEDIATE_EXIT: Immediate exit on signal (required for Base Blueprint)
|
|
61
|
+
STOP_LOSS: Fixed stop loss
|
|
62
|
+
TAKE_PROFIT: Fixed take profit
|
|
63
|
+
TRAILING_STOP: Dynamic trailing stop
|
|
64
|
+
BREAKEVEN: Move stop to breakeven after profit
|
|
65
|
+
TIMEOUT_EXIT: Exit after time limit
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
IMMEDIATE_ENTRY = "ImmediateEntry"
|
|
69
|
+
FAVORABLE_DELAY_ENTRY = "FavorableDelayEntry"
|
|
70
|
+
ADVERSE_DELAY_ENTRY = "AdverseDelayEntry"
|
|
71
|
+
IMMEDIATE_EXIT = "ImmediateExit"
|
|
72
|
+
STOP_LOSS = "StopLoss"
|
|
73
|
+
TAKE_PROFIT = "TakeProfit"
|
|
74
|
+
TRAILING_STOP = "TrailingStop"
|
|
75
|
+
BREAKEVEN = "Breakeven"
|
|
76
|
+
TIMEOUT_EXIT = "TimeoutExit"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class Weekday(str, Enum):
|
|
80
|
+
"""
|
|
81
|
+
Weekday enum (aligned with Rust Weekday enum)
|
|
82
|
+
|
|
83
|
+
Used for Market Profile WeeklyTime configuration.
|
|
84
|
+
|
|
85
|
+
Mapping:
|
|
86
|
+
MON (Monday) = 0
|
|
87
|
+
TUE (Tuesday) = 1
|
|
88
|
+
WED (Wednesday) = 2
|
|
89
|
+
THU (Thursday) = 3
|
|
90
|
+
FRI (Friday) = 4
|
|
91
|
+
SAT (Saturday) = 5
|
|
92
|
+
SUN (Sunday) = 6
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
MON = "Mon"
|
|
96
|
+
TUE = "Tue"
|
|
97
|
+
WED = "Wed"
|
|
98
|
+
THU = "Thu"
|
|
99
|
+
FRI = "Fri"
|
|
100
|
+
SAT = "Sat"
|
|
101
|
+
SUN = "Sun"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class IndicatorType(str, Enum):
|
|
105
|
+
"""
|
|
106
|
+
Indicator type enum
|
|
107
|
+
|
|
108
|
+
Maps to Indicator factory methods in models.py.
|
|
109
|
+
|
|
110
|
+
Values:
|
|
111
|
+
SMA: Simple Moving Average
|
|
112
|
+
EMA: Exponential Moving Average
|
|
113
|
+
SMMA: Smoothed Moving Average
|
|
114
|
+
WMA: Weighted Moving Average
|
|
115
|
+
ATR: Average True Range
|
|
116
|
+
ATR_QUANTILE: ATR Rolling Quantile
|
|
117
|
+
SUPERTREND: SuperTrend
|
|
118
|
+
MARKET_PROFILE: Market Profile
|
|
119
|
+
CCI: Commodity Channel Index
|
|
120
|
+
RSI: Relative Strength Index
|
|
121
|
+
BOLLINGER_BANDS: Bollinger Bands
|
|
122
|
+
MACD: Moving Average Convergence Divergence
|
|
123
|
+
STOCHASTIC: Stochastic Oscillator
|
|
124
|
+
ADX: Average Directional Index
|
|
125
|
+
RAW_OHLCV: Raw OHLCV column
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
SMA = "sma"
|
|
129
|
+
EMA = "ema"
|
|
130
|
+
SMMA = "smma"
|
|
131
|
+
WMA = "wma"
|
|
132
|
+
ATR = "atr"
|
|
133
|
+
ATR_QUANTILE = "atr_quantile"
|
|
134
|
+
SUPERTREND = "supertrend"
|
|
135
|
+
MARKET_PROFILE = "market_profile"
|
|
136
|
+
CCI = "cci"
|
|
137
|
+
RSI = "rsi"
|
|
138
|
+
BOLLINGER_BANDS = "bollinger_bands"
|
|
139
|
+
MACD = "macd"
|
|
140
|
+
STOCHASTIC = "stochastic"
|
|
141
|
+
ADX = "adx"
|
|
142
|
+
RAW_OHLCV = "raw_ohlcv"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class TradeDirection(str, Enum):
|
|
146
|
+
"""
|
|
147
|
+
Trade direction enum
|
|
148
|
+
|
|
149
|
+
Used to specify the trading direction in Blueprint.
|
|
150
|
+
|
|
151
|
+
Values:
|
|
152
|
+
LONG: Long trades only
|
|
153
|
+
SHORT: Short trades only
|
|
154
|
+
BOTH: Both long and short trades (currently not fully supported)
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
LONG = "Long"
|
|
158
|
+
SHORT = "Short"
|
|
159
|
+
BOTH = "Both"
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class TrendType(str, Enum):
|
|
163
|
+
"""
|
|
164
|
+
Trend type enum
|
|
165
|
+
|
|
166
|
+
Used to categorize strategy trading style.
|
|
167
|
+
|
|
168
|
+
Values:
|
|
169
|
+
TREND: Trend-following strategies
|
|
170
|
+
RANGE: Range-bound/mean-reversion strategies
|
|
171
|
+
REVERSAL: Reversal/counter-trend strategies
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
TREND = "Trend"
|
|
175
|
+
RANGE = "Range"
|
|
176
|
+
REVERSAL = "Reversal"
|
tradepose_client/models.py
CHANGED
|
@@ -9,79 +9,13 @@ Pydantic 模型用於策略配置 (V2 - 自動轉換版本)
|
|
|
9
9
|
import json
|
|
10
10
|
from enum import Enum
|
|
11
11
|
from io import StringIO
|
|
12
|
-
from typing import Any, Dict, List,
|
|
12
|
+
from typing import Any, Dict, List, Optional, Union
|
|
13
13
|
|
|
14
14
|
import polars as pl
|
|
15
15
|
from pydantic import BaseModel, Field, field_serializer, field_validator
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"""時間頻率枚舉(與 Rust Freq enum 一致)
|
|
20
|
-
|
|
21
|
-
對應 Rust 的 Freq enum
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
MIN_1 = "1min"
|
|
25
|
-
MIN_5 = "5min"
|
|
26
|
-
MIN_15 = "15min"
|
|
27
|
-
MIN_30 = "30min"
|
|
28
|
-
HOUR_1 = "1h"
|
|
29
|
-
HOUR_4 = "4h"
|
|
30
|
-
DAY_1 = "1D"
|
|
31
|
-
WEEK_1 = "1W"
|
|
32
|
-
MONTH_1 = "1M"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class OrderStrategy(str, Enum):
|
|
36
|
-
"""訂單策略枚舉(與 Rust OrderStrategy enum 一致)
|
|
37
|
-
|
|
38
|
-
對應 Rust 的 OrderStrategy enum,使用字符串值以便 JSON 序列化
|
|
39
|
-
|
|
40
|
-
Rust 對應關係:
|
|
41
|
-
- Rust: OrderStrategy::ImmediateEntry → Python: OrderStrategy.IMMEDIATE_ENTRY (u32: 0)
|
|
42
|
-
- Rust: OrderStrategy::FavorableDelayEntry → Python: OrderStrategy.FAVORABLE_DELAY_ENTRY (u32: 1)
|
|
43
|
-
- Rust: OrderStrategy::AdverseDelayEntry → Python: OrderStrategy.ADVERSE_DELAY_ENTRY (u32: 2)
|
|
44
|
-
- Rust: OrderStrategy::ImmediateExit → Python: OrderStrategy.IMMEDIATE_EXIT (u32: 3)
|
|
45
|
-
- Rust: OrderStrategy::StopLoss → Python: OrderStrategy.STOP_LOSS (u32: 4)
|
|
46
|
-
- Rust: OrderStrategy::TakeProfit → Python: OrderStrategy.TAKE_PROFIT (u32: 5)
|
|
47
|
-
- Rust: OrderStrategy::TrailingStop → Python: OrderStrategy.TRAILING_STOP (u32: 6)
|
|
48
|
-
- Rust: OrderStrategy::Breakeven → Python: OrderStrategy.BREAKEVEN (u32: 7)
|
|
49
|
-
- Rust: OrderStrategy::TimeoutExit → Python: OrderStrategy.TIMEOUT_EXIT (u32: 8)
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
IMMEDIATE_ENTRY = "ImmediateEntry"
|
|
53
|
-
FAVORABLE_DELAY_ENTRY = "FavorableDelayEntry"
|
|
54
|
-
ADVERSE_DELAY_ENTRY = "AdverseDelayEntry"
|
|
55
|
-
IMMEDIATE_EXIT = "ImmediateExit"
|
|
56
|
-
STOP_LOSS = "StopLoss"
|
|
57
|
-
TAKE_PROFIT = "TakeProfit"
|
|
58
|
-
TRAILING_STOP = "TrailingStop"
|
|
59
|
-
BREAKEVEN = "Breakeven"
|
|
60
|
-
TIMEOUT_EXIT = "TimeoutExit"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class Weekday(str, Enum):
|
|
64
|
-
"""星期列舉(與 Rust Weekday enum 一致)
|
|
65
|
-
|
|
66
|
-
用於 Market Profile 的 WeeklyTime 配置
|
|
67
|
-
|
|
68
|
-
對應關係:
|
|
69
|
-
- 0 (週一) → "Mon"
|
|
70
|
-
- 1 (週二) → "Tue"
|
|
71
|
-
- 2 (週三) → "Wed"
|
|
72
|
-
- 3 (週四) → "Thu"
|
|
73
|
-
- 4 (週五) → "Fri"
|
|
74
|
-
- 5 (週六) → "Sat"
|
|
75
|
-
- 6 (週日) → "Sun"
|
|
76
|
-
"""
|
|
77
|
-
|
|
78
|
-
MON = "Mon"
|
|
79
|
-
TUE = "Tue"
|
|
80
|
-
WED = "Wed"
|
|
81
|
-
THU = "Thu"
|
|
82
|
-
FRI = "Fri"
|
|
83
|
-
SAT = "Sat"
|
|
84
|
-
SUN = "Sun"
|
|
17
|
+
# Import enums from enums.py
|
|
18
|
+
from .enums import Freq, OrderStrategy, Weekday, TradeDirection, TrendType
|
|
85
19
|
|
|
86
20
|
|
|
87
21
|
class PolarsExprField:
|
|
@@ -1425,8 +1359,8 @@ class Blueprint(BaseModel):
|
|
|
1425
1359
|
"""策略藍圖"""
|
|
1426
1360
|
|
|
1427
1361
|
name: str = Field(..., description="藍圖名稱")
|
|
1428
|
-
direction:
|
|
1429
|
-
trend_type:
|
|
1362
|
+
direction: Union[TradeDirection, str] = Field(..., description="方向")
|
|
1363
|
+
trend_type: Union[TrendType, str] = Field(
|
|
1430
1364
|
..., description="趨勢類型"
|
|
1431
1365
|
)
|
|
1432
1366
|
entry_first: bool = Field(..., description="是否優先進場")
|
|
@@ -1654,10 +1588,10 @@ def create_trigger(
|
|
|
1654
1588
|
|
|
1655
1589
|
def create_blueprint(
|
|
1656
1590
|
name: str,
|
|
1657
|
-
direction:
|
|
1591
|
+
direction: Union[TradeDirection, str],
|
|
1658
1592
|
entry_triggers: List[Trigger],
|
|
1659
1593
|
exit_triggers: List[Trigger],
|
|
1660
|
-
trend_type:
|
|
1594
|
+
trend_type: Union[TrendType, str] = "Trend",
|
|
1661
1595
|
entry_first: bool = True,
|
|
1662
1596
|
note: str = "",
|
|
1663
1597
|
) -> Blueprint:
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
tradepose_client/__init__.py,sha256=51JWgNgRTfKzm52NVCb9VT7rQcGd20f2DoLuF6RzReA,3907
|
|
2
|
+
tradepose_client/analysis.py,sha256=RNpk3i9_1uUXM_-K-xYbG3Ckg-MoOwQ6gSExua2N4N8,7563
|
|
3
|
+
tradepose_client/client.py,sha256=1qD4pnIjCXKgE3VXeB6EgkNuCXvDJEbmPldIjIzAVmk,1798
|
|
4
|
+
tradepose_client/enums.py,sha256=Dhvwj_diX8r_ByerwZpDSqAsquRI5FMOctm7RxQ1CDA,4887
|
|
5
|
+
tradepose_client/models.py,sha256=Fp2Brop-5R5Oo-HmWk_JXvB6oS21wH5bvEM0Akj4FWM,64196
|
|
6
|
+
tradepose_client/schema.py,sha256=lPcJU-1xKcGFRoeuvqovrg4LUiOLO5bRZiMVyDkKHUQ,6357
|
|
7
|
+
tradepose_client/viz.py,sha256=qu9zyAXa_Q7D4rxdgN55JyYiY24ZD3r0jf2SWtqGZYg,22989
|
|
8
|
+
tradepose_client/api/__init__.py,sha256=ezeMxOBrUDRhlqZNO-X0X9KbNJGccDseKQ95zAvyhFY,218
|
|
9
|
+
tradepose_client/api/engine.py,sha256=IRmQPu7ECfFeIkve2b3txxt_D--v4arHvsVRZ0orx1w,1423
|
|
10
|
+
tradepose_client/api/export.py,sha256=gYW6yIHm1e0HZxvUA4k15tYqLfrihmssosJ2vXimT5k,27838
|
|
11
|
+
tradepose_client/api/health.py,sha256=NBZstYvVQszxDOstCmBt3A3anjNv7wuCsMOjup0DS5g,1889
|
|
12
|
+
tradepose_client/api/strategy.py,sha256=7cPurXqf9XCxyxSHaG_78GmEtg-KNJJhzNZNdn93ji8,7316
|
|
13
|
+
tradepose_client/builder/__init__.py,sha256=PIrsZcxP5cEa2_K1Zzpcf2FVc62iavKCNT6D8JbXaGU,643
|
|
14
|
+
tradepose_client/builder/blueprint_builder.py,sha256=7ssa3J3AMezZlWEyGbkaSfwhIyGPIzgl1bOKY7owZg4,9347
|
|
15
|
+
tradepose_client/builder/indicator_wrapper.py,sha256=zfVZE1fX-2emUg8bSjlukP9rF47j8s7h2efo_fSVWWM,3581
|
|
16
|
+
tradepose_client/builder/strategy_builder.py,sha256=gEeNytZepy3t4jmPKFcZZv3lGSBC0SMQ1QCTcv-qOO0,10433
|
|
17
|
+
tradepose_client/builder/trading_context.py,sha256=Z8ueMqAyUQmiUQsAQ8qrAipWkOMFdnEkpeazhFpnf1A,5318
|
|
18
|
+
tradepose_client-0.1.1.dist-info/METADATA,sha256=ar2oTs6oLE7SWXCMBSP8cGldrjfu3c5Ve6MBgn38-YI,14056
|
|
19
|
+
tradepose_client-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
20
|
+
tradepose_client-0.1.1.dist-info/licenses/LICENSE,sha256=6qYWNkUbxmJl1iN7c4DoM1_8ASsZyXemFO1D0wXtiHk,1071
|
|
21
|
+
tradepose_client-0.1.1.dist-info/RECORD,,
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
tradepose_client/__init__.py,sha256=cZL8Feo-ZkQ5bR7E-G7afg740Cu-oXaZ_s1ox6bPDqs,3549
|
|
2
|
-
tradepose_client/analysis.py,sha256=RNpk3i9_1uUXM_-K-xYbG3Ckg-MoOwQ6gSExua2N4N8,7563
|
|
3
|
-
tradepose_client/client.py,sha256=1qD4pnIjCXKgE3VXeB6EgkNuCXvDJEbmPldIjIzAVmk,1798
|
|
4
|
-
tradepose_client/models.py,sha256=j1UmUqGEIHObyAxfTETg5Kc83ipylr-Y0IivGuJB16M,66374
|
|
5
|
-
tradepose_client/schema.py,sha256=lPcJU-1xKcGFRoeuvqovrg4LUiOLO5bRZiMVyDkKHUQ,6357
|
|
6
|
-
tradepose_client/viz.py,sha256=qu9zyAXa_Q7D4rxdgN55JyYiY24ZD3r0jf2SWtqGZYg,22989
|
|
7
|
-
tradepose_client/api/__init__.py,sha256=ezeMxOBrUDRhlqZNO-X0X9KbNJGccDseKQ95zAvyhFY,218
|
|
8
|
-
tradepose_client/api/engine.py,sha256=IRmQPu7ECfFeIkve2b3txxt_D--v4arHvsVRZ0orx1w,1423
|
|
9
|
-
tradepose_client/api/export.py,sha256=gYW6yIHm1e0HZxvUA4k15tYqLfrihmssosJ2vXimT5k,27838
|
|
10
|
-
tradepose_client/api/health.py,sha256=NBZstYvVQszxDOstCmBt3A3anjNv7wuCsMOjup0DS5g,1889
|
|
11
|
-
tradepose_client/api/strategy.py,sha256=7cPurXqf9XCxyxSHaG_78GmEtg-KNJJhzNZNdn93ji8,7316
|
|
12
|
-
tradepose_client-0.1.0.dist-info/METADATA,sha256=Ked6fn17kxv90zUewN9-cGiv-wzCqFyT27YQMXhfv88,14056
|
|
13
|
-
tradepose_client-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
-
tradepose_client-0.1.0.dist-info/licenses/LICENSE,sha256=6qYWNkUbxmJl1iN7c4DoM1_8ASsZyXemFO1D0wXtiHk,1071
|
|
15
|
-
tradepose_client-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|