reportify-sdk 0.2.1__py3-none-any.whl → 0.2.3__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 +36 -8
- reportify_sdk/stock.py +36 -0
- {reportify_sdk-0.2.1.dist-info → reportify_sdk-0.2.3.dist-info}/METADATA +1 -1
- {reportify_sdk-0.2.1.dist-info → reportify_sdk-0.2.3.dist-info}/RECORD +7 -7
- {reportify_sdk-0.2.1.dist-info → reportify_sdk-0.2.3.dist-info}/WHEEL +1 -1
- {reportify_sdk-0.2.1.dist-info → reportify_sdk-0.2.3.dist-info}/licenses/LICENSE +0 -0
- {reportify_sdk-0.2.1.dist-info → reportify_sdk-0.2.3.dist-info}/top_level.txt +0 -0
reportify_sdk/quant.py
CHANGED
|
@@ -321,32 +321,36 @@ class QuantModule:
|
|
|
321
321
|
|
|
322
322
|
def backtest(
|
|
323
323
|
self,
|
|
324
|
-
symbol: str,
|
|
325
|
-
formula: str,
|
|
326
324
|
start_date: str,
|
|
327
325
|
end_date: str,
|
|
326
|
+
symbol: str,
|
|
327
|
+
entry_formula: str,
|
|
328
328
|
*,
|
|
329
|
+
exit_formula: str | None = None,
|
|
329
330
|
market: StockMarket = "cn",
|
|
330
331
|
initial_cash: float = 100000.0,
|
|
331
332
|
commission: float = 0.0,
|
|
332
333
|
stop_loss: float = 0.0,
|
|
333
334
|
sizer_percent: int = 99,
|
|
334
335
|
auto_close: bool = True,
|
|
336
|
+
labels: dict[str, str] | None = None,
|
|
335
337
|
) -> dict[str, Any]:
|
|
336
338
|
"""
|
|
337
339
|
Execute strategy backtest
|
|
338
340
|
|
|
339
341
|
Args:
|
|
340
|
-
symbol: Stock code
|
|
341
|
-
formula: Trading strategy formula using Mai-language syntax
|
|
342
342
|
start_date: Backtest start date (YYYY-MM-DD)
|
|
343
343
|
end_date: Backtest end date (YYYY-MM-DD)
|
|
344
|
+
symbol: Stock code
|
|
344
345
|
market: Stock market ("cn", "hk", "us"), default "cn"
|
|
346
|
+
entry_formula: Buy/long entry formula (result > 0 triggers buy)
|
|
347
|
+
exit_formula: Sell/close formula (result > 0 triggers sell), optional
|
|
345
348
|
initial_cash: Initial capital (default: 100000.0)
|
|
346
349
|
commission: Commission rate (default: 0.0)
|
|
347
350
|
stop_loss: Stop loss setting (default: 0.0, no stop loss)
|
|
348
351
|
sizer_percent: Position percentage (default: 99%)
|
|
349
352
|
auto_close: Auto close positions (default: True)
|
|
353
|
+
labels: Label dict for returning extra indicator values, e.g. {"up": "CROSS(MA(20), MA(60))"}
|
|
350
354
|
|
|
351
355
|
Returns:
|
|
352
356
|
Backtest results including:
|
|
@@ -362,29 +366,53 @@ class QuantModule:
|
|
|
362
366
|
- trades: List of trade details
|
|
363
367
|
|
|
364
368
|
Example:
|
|
369
|
+
>>> # Simple golden cross strategy
|
|
365
370
|
>>> result = client.quant.backtest(
|
|
366
|
-
... symbol="000001",
|
|
367
|
-
... formula="CROSS(MA(5), MA(20))", # Golden cross buy signal
|
|
368
371
|
... start_date="2023-01-01",
|
|
369
372
|
... end_date="2024-01-01",
|
|
373
|
+
... symbol="000001",
|
|
374
|
+
... entry_formula="CROSS(MA(5), MA(20))", # Buy when MA5 crosses above MA20
|
|
370
375
|
... initial_cash=100000
|
|
371
376
|
... )
|
|
372
377
|
>>> print(f"Total Return: {result['total_return_pct']:.2%}")
|
|
373
378
|
>>> print(f"Max Drawdown: {result['max_drawdown']:.2%}")
|
|
374
379
|
>>> print(f"Win Rate: {result['win_rate']:.2%}")
|
|
380
|
+
|
|
381
|
+
>>> # Strategy with entry and exit signals
|
|
382
|
+
>>> result = client.quant.backtest(
|
|
383
|
+
... start_date="2023-01-01",
|
|
384
|
+
... end_date="2024-01-01",
|
|
385
|
+
... symbol="000001",
|
|
386
|
+
... entry_formula="CROSS(MA(5), MA(20))", # Buy signal
|
|
387
|
+
... exit_formula="CROSSDOWN(MA(5), MA(20))" # Sell signal
|
|
388
|
+
... )
|
|
389
|
+
|
|
390
|
+
>>> # With custom labels for analysis
|
|
391
|
+
>>> result = client.quant.backtest(
|
|
392
|
+
... start_date="2023-01-01",
|
|
393
|
+
... end_date="2024-01-01",
|
|
394
|
+
... symbol="000001",
|
|
395
|
+
... entry_formula="RSI(14) < 30",
|
|
396
|
+
... exit_formula="RSI(14) > 70",
|
|
397
|
+
... labels={"rsi": "RSI(14)", "ma20": "MA(20)"}
|
|
398
|
+
... )
|
|
375
399
|
"""
|
|
376
400
|
data = {
|
|
377
|
-
"symbol": symbol,
|
|
378
|
-
"formula": formula,
|
|
379
401
|
"start_date": start_date,
|
|
380
402
|
"end_date": end_date,
|
|
403
|
+
"symbol": symbol,
|
|
381
404
|
"market": market,
|
|
405
|
+
"entry_formula": entry_formula,
|
|
382
406
|
"initial_cash": initial_cash,
|
|
383
407
|
"commission": commission,
|
|
384
408
|
"stop_loss": stop_loss,
|
|
385
409
|
"sizer_percent": sizer_percent,
|
|
386
410
|
"auto_close": auto_close,
|
|
387
411
|
}
|
|
412
|
+
if exit_formula is not None:
|
|
413
|
+
data["exit_formula"] = exit_formula
|
|
414
|
+
if labels is not None:
|
|
415
|
+
data["labels"] = labels
|
|
388
416
|
|
|
389
417
|
return self._client._post("/v1/quant/backtest", json=data)
|
|
390
418
|
|
reportify_sdk/stock.py
CHANGED
|
@@ -397,6 +397,42 @@ class StockModule:
|
|
|
397
397
|
response = self._post("/v1/stock/ipo-calendar-hk", json={"status": status})
|
|
398
398
|
return self._to_dataframe(response)
|
|
399
399
|
|
|
400
|
+
def industry_constituent(
|
|
401
|
+
self,
|
|
402
|
+
market: Literal["cn", "hk", "us"],
|
|
403
|
+
name: str,
|
|
404
|
+
*,
|
|
405
|
+
type: str | None = None,
|
|
406
|
+
) -> pd.DataFrame:
|
|
407
|
+
"""
|
|
408
|
+
Get constituent stocks of an industry
|
|
409
|
+
|
|
410
|
+
Args:
|
|
411
|
+
market: Stock market ("cn", "hk", "us")
|
|
412
|
+
name: Industry name (e.g., "军工", "Technology")
|
|
413
|
+
type: Industry classification type (optional)
|
|
414
|
+
- cn: "sw" (申万2021, default), "wind", "hs"
|
|
415
|
+
- hk: "hs" (恒生, default)
|
|
416
|
+
- us: "GICS" (default)
|
|
417
|
+
|
|
418
|
+
Returns:
|
|
419
|
+
DataFrame with industry constituent stocks
|
|
420
|
+
|
|
421
|
+
Example:
|
|
422
|
+
>>> # Get CN defense industry stocks
|
|
423
|
+
>>> stocks = client.stock.industry_constituent("cn", "军工")
|
|
424
|
+
>>> print(stocks[["symbol", "name", "industry_one_level_name"]])
|
|
425
|
+
|
|
426
|
+
>>> # Get US technology stocks using GICS
|
|
427
|
+
>>> stocks = client.stock.industry_constituent("us", "Technology")
|
|
428
|
+
"""
|
|
429
|
+
data = {"market": market, "name": name}
|
|
430
|
+
if type:
|
|
431
|
+
data["type"] = type
|
|
432
|
+
|
|
433
|
+
response = self._post("/v1/stock/industry-constituent", json=data)
|
|
434
|
+
return self._to_dataframe(response)
|
|
435
|
+
|
|
400
436
|
# -------------------------------------------------------------------------
|
|
401
437
|
# Helper Methods
|
|
402
438
|
# -------------------------------------------------------------------------
|
|
@@ -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=
|
|
7
|
-
reportify_sdk/stock.py,sha256=
|
|
6
|
+
reportify_sdk/quant.py,sha256=9rWKWo2UlG3GfsQC-jpEgXUl25ojEabpvOGISyGMamM,15110
|
|
7
|
+
reportify_sdk/stock.py,sha256=zqPshC1uZzlfnOyJmDfDlb7FX2FedcBCyJ_nuXa34jE,14747
|
|
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.3.dist-info/licenses/LICENSE,sha256=zBUq4DL4lE-fZU_PMkr0gnxkYS1LhdRHFw8_LmCb-ek,1066
|
|
10
|
+
reportify_sdk-0.2.3.dist-info/METADATA,sha256=yObxTM5fOBMULJFN9o9Y3NfXAr2BbaSOsevKXa0Q2XE,4311
|
|
11
|
+
reportify_sdk-0.2.3.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
12
|
+
reportify_sdk-0.2.3.dist-info/top_level.txt,sha256=tc_dzCSWIDsNbHSi-FlyEEX8xwinhN9gl-CwyLRE4B0,14
|
|
13
|
+
reportify_sdk-0.2.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|