reportify-sdk 0.2.0__py3-none-any.whl → 0.2.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.
- reportify_sdk/quant.py +229 -196
- {reportify_sdk-0.2.0.dist-info → reportify_sdk-0.2.1.dist-info}/METADATA +1 -1
- {reportify_sdk-0.2.0.dist-info → reportify_sdk-0.2.1.dist-info}/RECORD +6 -6
- {reportify_sdk-0.2.0.dist-info → reportify_sdk-0.2.1.dist-info}/WHEEL +0 -0
- {reportify_sdk-0.2.0.dist-info → reportify_sdk-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {reportify_sdk-0.2.0.dist-info → reportify_sdk-0.2.1.dist-info}/top_level.txt +0 -0
reportify_sdk/quant.py
CHANGED
|
@@ -2,22 +2,30 @@
|
|
|
2
2
|
Quant Module
|
|
3
3
|
|
|
4
4
|
Provides quantitative analysis tools including indicators, factors, quotes, and backtesting.
|
|
5
|
+
Based on Mai-language syntax compatible with TongDaXin/TongHuaShun.
|
|
5
6
|
"""
|
|
6
7
|
|
|
7
|
-
from typing import Any
|
|
8
|
+
from typing import Any, Literal
|
|
8
9
|
|
|
9
10
|
import pandas as pd
|
|
10
11
|
|
|
11
12
|
|
|
13
|
+
StockMarket = Literal["cn", "hk", "us"]
|
|
14
|
+
|
|
15
|
+
|
|
12
16
|
class QuantModule:
|
|
13
17
|
"""
|
|
14
18
|
Quantitative analysis module
|
|
15
19
|
|
|
16
|
-
Access technical indicators, factors, quotes, and backtesting functionality.
|
|
20
|
+
Access technical indicators, factors, OHLCV quotes, and backtesting functionality.
|
|
21
|
+
Uses Mai-language syntax for formulas.
|
|
17
22
|
|
|
18
23
|
Example:
|
|
19
24
|
>>> quant = client.quant
|
|
20
|
-
>>>
|
|
25
|
+
>>> # Compute RSI indicator
|
|
26
|
+
>>> df = quant.compute_indicators(["000001"], "RSI(14)")
|
|
27
|
+
>>> # Screen stocks by formula
|
|
28
|
+
>>> stocks = quant.screen(formula="RSI(14) < 30")
|
|
21
29
|
"""
|
|
22
30
|
|
|
23
31
|
def __init__(self, client):
|
|
@@ -27,231 +35,285 @@ class QuantModule:
|
|
|
27
35
|
# Indicators
|
|
28
36
|
# -------------------------------------------------------------------------
|
|
29
37
|
|
|
30
|
-
def
|
|
38
|
+
def list_indicators(self) -> list[dict[str, Any]]:
|
|
39
|
+
"""
|
|
40
|
+
Get list of available technical indicators
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
List of indicator definitions with name, description, and fields
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
>>> indicators = client.quant.list_indicators()
|
|
47
|
+
>>> for ind in indicators:
|
|
48
|
+
... print(f"{ind['name']}: {ind['description']}")
|
|
49
|
+
... print(f" Fields: {ind['fields']}")
|
|
50
|
+
"""
|
|
51
|
+
return self._client._get("/v1/quant/indicators")
|
|
52
|
+
|
|
53
|
+
def compute_indicators(
|
|
31
54
|
self,
|
|
32
55
|
symbols: list[str],
|
|
33
|
-
|
|
56
|
+
formula: str,
|
|
34
57
|
*,
|
|
58
|
+
market: StockMarket = "cn",
|
|
35
59
|
start_date: str | None = None,
|
|
36
60
|
end_date: str | None = None,
|
|
37
|
-
interval: str = "1d",
|
|
38
|
-
params: dict[str, Any] | None = None,
|
|
39
61
|
) -> pd.DataFrame:
|
|
40
62
|
"""
|
|
41
|
-
|
|
63
|
+
Compute indicator values for given symbols
|
|
42
64
|
|
|
43
65
|
Args:
|
|
44
|
-
symbols: List of stock
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
params: Additional indicator parameters (e.g., {"ma_period": 20})
|
|
66
|
+
symbols: List of stock codes (e.g., ["000001", "600519"])
|
|
67
|
+
formula: Indicator formula (e.g., "RSI(14)", "MACD()", "MACD(12,26,9)")
|
|
68
|
+
market: Stock market ("cn", "hk", "us"), default "cn"
|
|
69
|
+
start_date: Start date (YYYY-MM-DD), default 3 months ago
|
|
70
|
+
end_date: End date (YYYY-MM-DD), default today
|
|
50
71
|
|
|
51
72
|
Returns:
|
|
52
73
|
DataFrame with indicator values
|
|
53
74
|
|
|
54
75
|
Example:
|
|
55
|
-
>>>
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
>>>
|
|
76
|
+
>>> # RSI indicator
|
|
77
|
+
>>> df = client.quant.compute_indicators(["000001"], "RSI(14)")
|
|
78
|
+
>>> print(df[["symbol", "date", "rsi"]])
|
|
79
|
+
|
|
80
|
+
>>> # MACD indicator
|
|
81
|
+
>>> df = client.quant.compute_indicators(["000001"], "MACD()")
|
|
82
|
+
>>> print(df[["symbol", "date", "dif", "dea", "macd"]])
|
|
83
|
+
|
|
84
|
+
>>> # KDJ indicator
|
|
85
|
+
>>> df = client.quant.compute_indicators(["000001"], "KDJ(9,3,3)")
|
|
86
|
+
>>> print(df[["symbol", "date", "k", "d", "j"]])
|
|
61
87
|
"""
|
|
62
88
|
data: dict[str, Any] = {
|
|
63
89
|
"symbols": symbols,
|
|
64
|
-
"
|
|
65
|
-
"
|
|
90
|
+
"formula": formula,
|
|
91
|
+
"market": market,
|
|
66
92
|
}
|
|
67
93
|
if start_date:
|
|
68
94
|
data["start_date"] = start_date
|
|
69
95
|
if end_date:
|
|
70
96
|
data["end_date"] = end_date
|
|
71
|
-
if params:
|
|
72
|
-
data["params"] = params
|
|
73
97
|
|
|
74
|
-
response = self._client._post("/
|
|
75
|
-
return self._to_dataframe(response.get("
|
|
98
|
+
response = self._client._post("/v1/quant/indicators/compute", json=data)
|
|
99
|
+
return self._to_dataframe(response.get("datas", []))
|
|
100
|
+
|
|
101
|
+
# -------------------------------------------------------------------------
|
|
102
|
+
# Factors
|
|
103
|
+
# -------------------------------------------------------------------------
|
|
76
104
|
|
|
77
|
-
def
|
|
105
|
+
def list_factors(self) -> list[dict[str, Any]]:
|
|
78
106
|
"""
|
|
79
|
-
Get list of available
|
|
107
|
+
Get list of available factors (variables and functions)
|
|
108
|
+
|
|
109
|
+
Returns factors organized by level:
|
|
110
|
+
- Level 0 Variables: CLOSE, OPEN, HIGH, LOW, VOLUME
|
|
111
|
+
- Level 0 Functions: MA, EMA, REF, HHV, LLV, STD, etc.
|
|
112
|
+
- Level 1 Functions: CROSS, COUNT, EVERY, etc.
|
|
113
|
+
- Level 2 Functions: MACD, KDJ, RSI, BOLL, etc.
|
|
80
114
|
|
|
81
115
|
Returns:
|
|
82
|
-
List of
|
|
116
|
+
List of factor definitions
|
|
83
117
|
|
|
84
118
|
Example:
|
|
85
|
-
>>>
|
|
86
|
-
>>> for
|
|
87
|
-
... print(f"{
|
|
119
|
+
>>> factors = client.quant.list_factors()
|
|
120
|
+
>>> for f in factors:
|
|
121
|
+
... print(f"{f['name']} ({f['type']}, level {f['level']})")
|
|
88
122
|
"""
|
|
89
|
-
|
|
90
|
-
return response.get("indicators", [])
|
|
91
|
-
|
|
92
|
-
# -------------------------------------------------------------------------
|
|
93
|
-
# Factors
|
|
94
|
-
# -------------------------------------------------------------------------
|
|
123
|
+
return self._client._get("/v1/quant/factors")
|
|
95
124
|
|
|
96
|
-
def
|
|
125
|
+
def compute_factors(
|
|
97
126
|
self,
|
|
98
127
|
symbols: list[str],
|
|
99
|
-
|
|
128
|
+
formula: str,
|
|
100
129
|
*,
|
|
130
|
+
market: StockMarket = "cn",
|
|
101
131
|
start_date: str | None = None,
|
|
102
132
|
end_date: str | None = None,
|
|
103
|
-
frequency: str = "daily",
|
|
104
133
|
) -> pd.DataFrame:
|
|
105
134
|
"""
|
|
106
|
-
|
|
135
|
+
Compute factor values for given symbols
|
|
136
|
+
|
|
137
|
+
Uses Mai-language syntax compatible with TongDaXin/TongHuaShun.
|
|
107
138
|
|
|
108
139
|
Args:
|
|
109
|
-
symbols: List of stock
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
140
|
+
symbols: List of stock codes
|
|
141
|
+
formula: Factor formula using Mai-language syntax
|
|
142
|
+
market: Stock market ("cn", "hk", "us"), default "cn"
|
|
143
|
+
start_date: Start date (YYYY-MM-DD), default 3 months ago
|
|
144
|
+
end_date: End date (YYYY-MM-DD), default today
|
|
114
145
|
|
|
115
146
|
Returns:
|
|
116
147
|
DataFrame with factor values
|
|
117
148
|
|
|
118
149
|
Example:
|
|
119
|
-
>>>
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
150
|
+
>>> # Simple indicator
|
|
151
|
+
>>> df = client.quant.compute_factors(["000001"], "RSI(14)")
|
|
152
|
+
|
|
153
|
+
>>> # MACD DIF line
|
|
154
|
+
>>> df = client.quant.compute_factors(["000001"], "MACD().dif")
|
|
155
|
+
|
|
156
|
+
>>> # Close above 20-day MA (boolean)
|
|
157
|
+
>>> df = client.quant.compute_factors(["000001"], "CLOSE > MA(20)")
|
|
158
|
+
|
|
159
|
+
>>> # Deviation from MA20 in percent
|
|
160
|
+
>>> df = client.quant.compute_factors(["000001"], "(CLOSE - MA(20)) / MA(20) * 100")
|
|
161
|
+
|
|
162
|
+
Supported Operators:
|
|
163
|
+
- Comparison: >, <, >=, <=, ==, !=
|
|
164
|
+
- Logical AND: & (NOT "AND")
|
|
165
|
+
- Logical OR: | (NOT "OR")
|
|
166
|
+
- Arithmetic: +, -, *, /
|
|
167
|
+
|
|
168
|
+
Supported Variables:
|
|
169
|
+
- CLOSE, C: Close price
|
|
170
|
+
- OPEN, O: Open price
|
|
171
|
+
- HIGH, H: High price
|
|
172
|
+
- LOW, L: Low price
|
|
173
|
+
- VOLUME, V, VOL: Volume
|
|
124
174
|
"""
|
|
125
175
|
data: dict[str, Any] = {
|
|
126
176
|
"symbols": symbols,
|
|
127
|
-
"
|
|
128
|
-
"
|
|
177
|
+
"formula": formula,
|
|
178
|
+
"market": market,
|
|
129
179
|
}
|
|
130
180
|
if start_date:
|
|
131
181
|
data["start_date"] = start_date
|
|
132
182
|
if end_date:
|
|
133
183
|
data["end_date"] = end_date
|
|
134
184
|
|
|
135
|
-
response = self._client._post("/
|
|
136
|
-
return self._to_dataframe(response.get("
|
|
137
|
-
|
|
138
|
-
def factor_list(self) -> list[dict[str, Any]]:
|
|
139
|
-
"""
|
|
140
|
-
Get list of available factors
|
|
141
|
-
|
|
142
|
-
Returns:
|
|
143
|
-
List of factor definitions
|
|
144
|
-
|
|
145
|
-
Example:
|
|
146
|
-
>>> factors = client.quant.factor_list()
|
|
147
|
-
>>> for f in factors:
|
|
148
|
-
... print(f"{f['name']}: {f['category']}")
|
|
149
|
-
"""
|
|
150
|
-
response = self._client._get("/v2/quant/factors")
|
|
151
|
-
return response.get("factors", [])
|
|
185
|
+
response = self._client._post("/v1/quant/factors/compute", json=data)
|
|
186
|
+
return self._to_dataframe(response.get("datas", []))
|
|
152
187
|
|
|
153
|
-
def
|
|
188
|
+
def screen(
|
|
154
189
|
self,
|
|
155
|
-
|
|
190
|
+
formula: str,
|
|
156
191
|
*,
|
|
157
|
-
|
|
192
|
+
market: StockMarket = "cn",
|
|
193
|
+
check_date: str | None = None,
|
|
194
|
+
symbols: list[str] | None = None,
|
|
158
195
|
) -> pd.DataFrame:
|
|
159
196
|
"""
|
|
160
|
-
|
|
197
|
+
Screen stocks based on factor formula
|
|
198
|
+
|
|
199
|
+
Returns stocks where the formula evaluates to True (for boolean formulas)
|
|
200
|
+
or non-null (for numeric formulas).
|
|
161
201
|
|
|
162
202
|
Args:
|
|
163
|
-
|
|
164
|
-
|
|
203
|
+
formula: Screening formula using Mai-language syntax
|
|
204
|
+
market: Stock market ("cn", "hk", "us"), default "cn"
|
|
205
|
+
check_date: Check date (YYYY-MM-DD), default latest trading day
|
|
206
|
+
symbols: Stock codes to screen (None = full market)
|
|
165
207
|
|
|
166
208
|
Returns:
|
|
167
|
-
DataFrame with
|
|
209
|
+
DataFrame with stocks that passed the filter
|
|
168
210
|
|
|
169
211
|
Example:
|
|
170
|
-
>>>
|
|
171
|
-
>>>
|
|
212
|
+
>>> # RSI oversold
|
|
213
|
+
>>> stocks = client.quant.screen(formula="RSI(14) < 30")
|
|
214
|
+
|
|
215
|
+
>>> # Golden cross
|
|
216
|
+
>>> stocks = client.quant.screen(formula="CROSS(MA(5), MA(10))")
|
|
217
|
+
|
|
218
|
+
>>> # Uptrend
|
|
219
|
+
>>> stocks = client.quant.screen(formula="(CLOSE > MA(20)) & (MA(20) > MA(60))")
|
|
220
|
+
|
|
221
|
+
>>> # Above upper Bollinger Band
|
|
222
|
+
>>> stocks = client.quant.screen(formula="CLOSE > BOLL(20, 2).upper")
|
|
223
|
+
|
|
224
|
+
>>> # Screen specific stocks
|
|
225
|
+
>>> stocks = client.quant.screen(
|
|
226
|
+
... formula="RSI(14) < 30",
|
|
227
|
+
... symbols=["000001", "600519", "000002"]
|
|
228
|
+
... )
|
|
172
229
|
"""
|
|
173
|
-
data: dict[str, Any] = {
|
|
174
|
-
|
|
175
|
-
|
|
230
|
+
data: dict[str, Any] = {
|
|
231
|
+
"formula": formula,
|
|
232
|
+
"market": market,
|
|
233
|
+
}
|
|
234
|
+
if check_date:
|
|
235
|
+
data["check_date"] = check_date
|
|
236
|
+
if symbols:
|
|
237
|
+
data["symbols"] = symbols
|
|
176
238
|
|
|
177
|
-
response = self._client._post("/
|
|
178
|
-
return self._to_dataframe(response.get("
|
|
239
|
+
response = self._client._post("/v1/quant/factors/screen", json=data)
|
|
240
|
+
return self._to_dataframe(response.get("datas", []))
|
|
179
241
|
|
|
180
242
|
# -------------------------------------------------------------------------
|
|
181
243
|
# Quotes
|
|
182
244
|
# -------------------------------------------------------------------------
|
|
183
245
|
|
|
184
|
-
def
|
|
246
|
+
def ohlcv(
|
|
185
247
|
self,
|
|
186
|
-
|
|
248
|
+
symbol: str,
|
|
187
249
|
*,
|
|
188
|
-
|
|
250
|
+
market: StockMarket = "cn",
|
|
251
|
+
start_date: str | None = None,
|
|
252
|
+
end_date: str | None = None,
|
|
189
253
|
) -> pd.DataFrame:
|
|
190
254
|
"""
|
|
191
|
-
Get
|
|
255
|
+
Get OHLCV (Open, High, Low, Close, Volume) daily data for a single symbol
|
|
192
256
|
|
|
193
257
|
Args:
|
|
194
|
-
|
|
195
|
-
|
|
258
|
+
symbol: Stock code
|
|
259
|
+
market: Stock market ("cn", "hk", "us"), default "cn"
|
|
260
|
+
start_date: Start date (YYYY-MM-DD), default 1 month ago
|
|
261
|
+
end_date: End date (YYYY-MM-DD), default today
|
|
196
262
|
|
|
197
263
|
Returns:
|
|
198
|
-
DataFrame with
|
|
264
|
+
DataFrame with OHLCV data
|
|
199
265
|
|
|
200
266
|
Example:
|
|
201
|
-
>>>
|
|
202
|
-
>>> print(
|
|
267
|
+
>>> df = client.quant.ohlcv("000001")
|
|
268
|
+
>>> print(df[["open", "high", "low", "close", "volume"]])
|
|
203
269
|
"""
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
270
|
+
params: dict[str, Any] = {
|
|
271
|
+
"symbol": symbol,
|
|
272
|
+
"market": market,
|
|
273
|
+
}
|
|
274
|
+
if start_date:
|
|
275
|
+
params["start_date"] = start_date
|
|
276
|
+
if end_date:
|
|
277
|
+
params["end_date"] = end_date
|
|
207
278
|
|
|
208
|
-
response = self._client.
|
|
209
|
-
return self._to_dataframe(response.get("
|
|
279
|
+
response = self._client._get("/v1/quant/quotes/ohlcv", params=params)
|
|
280
|
+
return self._to_dataframe(response.get("datas", []))
|
|
210
281
|
|
|
211
|
-
def
|
|
282
|
+
def ohlcv_batch(
|
|
212
283
|
self,
|
|
213
284
|
symbols: list[str],
|
|
214
285
|
*,
|
|
286
|
+
market: StockMarket = "cn",
|
|
215
287
|
start_date: str | None = None,
|
|
216
288
|
end_date: str | None = None,
|
|
217
|
-
interval: str = "1d",
|
|
218
|
-
adjust: str = "forward",
|
|
219
|
-
limit: int = 100,
|
|
220
289
|
) -> pd.DataFrame:
|
|
221
290
|
"""
|
|
222
|
-
Get
|
|
291
|
+
Get OHLCV data for multiple symbols
|
|
223
292
|
|
|
224
293
|
Args:
|
|
225
|
-
symbols: List of stock
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
adjust: Adjustment type ("forward", "backward", "none")
|
|
230
|
-
limit: Maximum records per symbol
|
|
294
|
+
symbols: List of stock codes
|
|
295
|
+
market: Stock market ("cn", "hk", "us"), default "cn"
|
|
296
|
+
start_date: Start date (YYYY-MM-DD), default 1 month ago
|
|
297
|
+
end_date: End date (YYYY-MM-DD), default today
|
|
231
298
|
|
|
232
299
|
Returns:
|
|
233
|
-
DataFrame with
|
|
300
|
+
DataFrame with OHLCV data sorted by date (descending), then by symbol
|
|
234
301
|
|
|
235
302
|
Example:
|
|
236
|
-
>>>
|
|
237
|
-
|
|
238
|
-
... start_date="2024-01-01",
|
|
239
|
-
... interval="1d"
|
|
240
|
-
... )
|
|
303
|
+
>>> df = client.quant.ohlcv_batch(["000001", "600519"])
|
|
304
|
+
>>> print(df[["symbol", "date", "close", "volume"]])
|
|
241
305
|
"""
|
|
242
306
|
data: dict[str, Any] = {
|
|
243
307
|
"symbols": symbols,
|
|
244
|
-
"
|
|
245
|
-
"adjust": adjust,
|
|
246
|
-
"limit": limit,
|
|
308
|
+
"market": market,
|
|
247
309
|
}
|
|
248
310
|
if start_date:
|
|
249
311
|
data["start_date"] = start_date
|
|
250
312
|
if end_date:
|
|
251
313
|
data["end_date"] = end_date
|
|
252
314
|
|
|
253
|
-
response = self._client._post("/
|
|
254
|
-
return self._to_dataframe(response.get("
|
|
315
|
+
response = self._client._post("/v1/quant/quotes/ohlcv/batch", json=data)
|
|
316
|
+
return self._to_dataframe(response.get("datas", []))
|
|
255
317
|
|
|
256
318
|
# -------------------------------------------------------------------------
|
|
257
319
|
# Backtest
|
|
@@ -259,99 +321,72 @@ class QuantModule:
|
|
|
259
321
|
|
|
260
322
|
def backtest(
|
|
261
323
|
self,
|
|
262
|
-
|
|
263
|
-
|
|
324
|
+
symbol: str,
|
|
325
|
+
formula: str,
|
|
264
326
|
start_date: str,
|
|
265
327
|
end_date: str,
|
|
266
|
-
|
|
267
|
-
|
|
328
|
+
*,
|
|
329
|
+
market: StockMarket = "cn",
|
|
330
|
+
initial_cash: float = 100000.0,
|
|
331
|
+
commission: float = 0.0,
|
|
332
|
+
stop_loss: float = 0.0,
|
|
333
|
+
sizer_percent: int = 99,
|
|
334
|
+
auto_close: bool = True,
|
|
268
335
|
) -> dict[str, Any]:
|
|
269
336
|
"""
|
|
270
|
-
|
|
337
|
+
Execute strategy backtest
|
|
271
338
|
|
|
272
339
|
Args:
|
|
273
|
-
|
|
340
|
+
symbol: Stock code
|
|
341
|
+
formula: Trading strategy formula using Mai-language syntax
|
|
274
342
|
start_date: Backtest start date (YYYY-MM-DD)
|
|
275
343
|
end_date: Backtest end date (YYYY-MM-DD)
|
|
276
|
-
|
|
277
|
-
|
|
344
|
+
market: Stock market ("cn", "hk", "us"), default "cn"
|
|
345
|
+
initial_cash: Initial capital (default: 100000.0)
|
|
346
|
+
commission: Commission rate (default: 0.0)
|
|
347
|
+
stop_loss: Stop loss setting (default: 0.0, no stop loss)
|
|
348
|
+
sizer_percent: Position percentage (default: 99%)
|
|
349
|
+
auto_close: Auto close positions (default: True)
|
|
278
350
|
|
|
279
351
|
Returns:
|
|
280
|
-
Backtest results including
|
|
352
|
+
Backtest results including:
|
|
353
|
+
- success: Whether backtest succeeded
|
|
354
|
+
- initial_cash: Initial capital
|
|
355
|
+
- final_cash: Final capital
|
|
356
|
+
- total_return: Total return
|
|
357
|
+
- total_return_pct: Total return percentage
|
|
358
|
+
- max_drawdown: Maximum drawdown
|
|
359
|
+
- profit_factor: Profit factor
|
|
360
|
+
- win_rate: Win rate
|
|
361
|
+
- total_trades: Total number of trades
|
|
362
|
+
- trades: List of trade details
|
|
281
363
|
|
|
282
364
|
Example:
|
|
283
365
|
>>> result = client.quant.backtest(
|
|
284
|
-
...
|
|
285
|
-
...
|
|
286
|
-
...
|
|
287
|
-
... "rebalance": "monthly",
|
|
288
|
-
... "top_n": 2
|
|
289
|
-
... },
|
|
290
|
-
... start_date="2020-01-01",
|
|
366
|
+
... symbol="000001",
|
|
367
|
+
... formula="CROSS(MA(5), MA(20))", # Golden cross buy signal
|
|
368
|
+
... start_date="2023-01-01",
|
|
291
369
|
... end_date="2024-01-01",
|
|
292
|
-
...
|
|
370
|
+
... initial_cash=100000
|
|
293
371
|
... )
|
|
294
|
-
>>> print(f"Total Return: {result['
|
|
372
|
+
>>> print(f"Total Return: {result['total_return_pct']:.2%}")
|
|
373
|
+
>>> print(f"Max Drawdown: {result['max_drawdown']:.2%}")
|
|
374
|
+
>>> print(f"Win Rate: {result['win_rate']:.2%}")
|
|
295
375
|
"""
|
|
296
376
|
data = {
|
|
297
|
-
"
|
|
377
|
+
"symbol": symbol,
|
|
378
|
+
"formula": formula,
|
|
298
379
|
"start_date": start_date,
|
|
299
380
|
"end_date": end_date,
|
|
300
|
-
"
|
|
381
|
+
"market": market,
|
|
382
|
+
"initial_cash": initial_cash,
|
|
383
|
+
"commission": commission,
|
|
384
|
+
"stop_loss": stop_loss,
|
|
385
|
+
"sizer_percent": sizer_percent,
|
|
386
|
+
"auto_close": auto_close,
|
|
301
387
|
}
|
|
302
|
-
if benchmark:
|
|
303
|
-
data["benchmark"] = benchmark
|
|
304
|
-
|
|
305
|
-
return self._client._post("/v2/quant/backtest", json=data)
|
|
306
|
-
|
|
307
|
-
def backtest_result(self, backtest_id: str) -> dict[str, Any]:
|
|
308
|
-
"""
|
|
309
|
-
Get backtest result by ID
|
|
310
388
|
|
|
311
|
-
|
|
312
|
-
backtest_id: Backtest job ID
|
|
313
|
-
|
|
314
|
-
Returns:
|
|
315
|
-
Backtest results
|
|
316
|
-
|
|
317
|
-
Example:
|
|
318
|
-
>>> result = client.quant.backtest_result("bt_abc123")
|
|
319
|
-
"""
|
|
320
|
-
return self._client._get(f"/v2/quant/backtest/{backtest_id}")
|
|
321
|
-
|
|
322
|
-
def backtest_returns(self, backtest_id: str) -> pd.DataFrame:
|
|
323
|
-
"""
|
|
324
|
-
Get backtest return series
|
|
325
|
-
|
|
326
|
-
Args:
|
|
327
|
-
backtest_id: Backtest job ID
|
|
328
|
-
|
|
329
|
-
Returns:
|
|
330
|
-
DataFrame with daily returns
|
|
331
|
-
|
|
332
|
-
Example:
|
|
333
|
-
>>> returns = client.quant.backtest_returns("bt_abc123")
|
|
334
|
-
>>> print(returns[["date", "portfolio_value", "daily_return"]])
|
|
335
|
-
"""
|
|
336
|
-
response = self._client._get(f"/v2/quant/backtest/{backtest_id}/returns")
|
|
337
|
-
return self._to_dataframe(response.get("data", []))
|
|
338
|
-
|
|
339
|
-
def backtest_trades(self, backtest_id: str) -> pd.DataFrame:
|
|
340
|
-
"""
|
|
341
|
-
Get backtest trade history
|
|
342
|
-
|
|
343
|
-
Args:
|
|
344
|
-
backtest_id: Backtest job ID
|
|
345
|
-
|
|
346
|
-
Returns:
|
|
347
|
-
DataFrame with all trades
|
|
348
|
-
|
|
349
|
-
Example:
|
|
350
|
-
>>> trades = client.quant.backtest_trades("bt_abc123")
|
|
351
|
-
>>> print(trades[["date", "symbol", "action", "quantity", "price"]])
|
|
352
|
-
"""
|
|
353
|
-
response = self._client._get(f"/v2/quant/backtest/{backtest_id}/trades")
|
|
354
|
-
return self._to_dataframe(response.get("data", []))
|
|
389
|
+
return self._client._post("/v1/quant/backtest", json=data)
|
|
355
390
|
|
|
356
391
|
# -------------------------------------------------------------------------
|
|
357
392
|
# Helper Methods
|
|
@@ -363,9 +398,7 @@ class QuantModule:
|
|
|
363
398
|
return pd.DataFrame()
|
|
364
399
|
df = pd.DataFrame(data)
|
|
365
400
|
# Convert date columns if present
|
|
366
|
-
for col in ["date", "
|
|
401
|
+
for col in ["date", "check_date", "trade_date"]:
|
|
367
402
|
if col in df.columns:
|
|
368
403
|
df[col] = pd.to_datetime(df[col])
|
|
369
|
-
df = df.set_index(col)
|
|
370
|
-
break
|
|
371
404
|
return df
|
|
@@ -3,11 +3,11 @@ reportify_sdk/client.py,sha256=P56qBme48UPkZhMb9BlDnLMLXwHK-DjU7qDhGFFxMI0,11019
|
|
|
3
3
|
reportify_sdk/docs.py,sha256=O30I1J4qTC8zpkVP_qu1cgT8nv6ysXNClqvaiRb0lhY,4957
|
|
4
4
|
reportify_sdk/exceptions.py,sha256=r2_C_kTh6tCrQnfA3UozSqMMA-2OBnoP3pGpgYeqcdU,1049
|
|
5
5
|
reportify_sdk/kb.py,sha256=-4UHWtudFncGRBB42B4YEoMPsEHr4QOtY55_8hKyogE,2240
|
|
6
|
-
reportify_sdk/quant.py,sha256=
|
|
6
|
+
reportify_sdk/quant.py,sha256=pEXvG0OH20SH37NoPu1Flm-Dz0FMoqch9_pLMOnXk8w,13777
|
|
7
7
|
reportify_sdk/stock.py,sha256=NcEhV9JfIQm2BsfYM1k-JVcxHhnnil32dp-bedGG4BU,13513
|
|
8
8
|
reportify_sdk/timeline.py,sha256=b5Zj5SjXT4gP0dvEl8gXCWDZJHemyU7NSYahet2nHhc,4075
|
|
9
|
-
reportify_sdk-0.2.
|
|
10
|
-
reportify_sdk-0.2.
|
|
11
|
-
reportify_sdk-0.2.
|
|
12
|
-
reportify_sdk-0.2.
|
|
13
|
-
reportify_sdk-0.2.
|
|
9
|
+
reportify_sdk-0.2.1.dist-info/licenses/LICENSE,sha256=zBUq4DL4lE-fZU_PMkr0gnxkYS1LhdRHFw8_LmCb-ek,1066
|
|
10
|
+
reportify_sdk-0.2.1.dist-info/METADATA,sha256=hEtOPPrQiLNFFiN_504fHs6Yb4H91fvPdeTE4uTq76E,4311
|
|
11
|
+
reportify_sdk-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
+
reportify_sdk-0.2.1.dist-info/top_level.txt,sha256=tc_dzCSWIDsNbHSi-FlyEEX8xwinhN9gl-CwyLRE4B0,14
|
|
13
|
+
reportify_sdk-0.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|