feat: add Quant OS A-share baseline

This commit is contained in:
2026-07-26 12:54:04 +08:00
commit 48c5f64bbd
98 changed files with 31874 additions and 0 deletions
+171
View File
@@ -0,0 +1,171 @@
import unittest
from quant60.portable_core import (
build_rebalance_plan,
capped_target_weights,
momentum_score,
normalize_symbol,
order_deltas,
target_quantities,
)
class PortableCoreTests(unittest.TestCase):
def test_symbol_round_trip(self):
inputs = [
("600000.XSHG", "600000.SH", "SH600000"),
("000001.XSHE", "000001.SZ", "SZ000001"),
("830799.XBSE", "830799.BJ", "BJ830799"),
]
for canonical, qmt, qlib in inputs:
self.assertEqual(normalize_symbol(qmt), canonical)
self.assertEqual(normalize_symbol(qlib), canonical)
self.assertEqual(normalize_symbol(canonical, "qmt"), qmt)
self.assertEqual(normalize_symbol(canonical, "qlib"), qlib)
def test_momentum_uses_latest_completed_bar(self):
self.assertAlmostEqual(momentum_score([10, 11, 12], 2, 0), 0.2)
self.assertAlmostEqual(momentum_score([10, 11, 12], 1, 1), 0.1)
def test_caps_and_cash_buffer_are_not_double_counted(self):
weights = capped_target_weights(
{"600000.XSHG": 3, "000001.XSHE": 2, "300750.XSHE": 1},
max_weight=0.4,
gross_target=0.95,
)
self.assertAlmostEqual(sum(weights.values()), 0.95)
self.assertLessEqual(max(weights.values()), 0.4 + 1e-12)
quantities = target_quantities(
weights,
{symbol: 10 for symbol in weights},
equity=1_000_000,
lot_size=100,
cash_buffer=0.02,
)
invested = sum(quantity * 10 for quantity in quantities.values())
self.assertGreater(invested, 930_000)
self.assertLessEqual(invested, 980_000)
def test_non_finite_or_out_of_range_portfolio_inputs_are_rejected(self):
for value in (float("nan"), float("inf"), float("-inf")):
with self.subTest(kind="score", value=value):
with self.assertRaises(ValueError):
capped_target_weights({"600000.SH": value})
with self.subTest(kind="weight", value=value):
with self.assertRaises(ValueError):
target_quantities(
{"600000.SH": value},
{"600000.SH": 10.0},
100_000,
)
with self.subTest(kind="equity", value=value):
with self.assertRaises(ValueError):
target_quantities(
{"600000.SH": 0.5},
{"600000.SH": 10.0},
value,
)
for max_weight, gross_target in ((1.1, 0.9), (0.2, 1.1)):
with self.subTest(max_weight=max_weight, gross_target=gross_target):
with self.assertRaises(ValueError):
capped_target_weights(
{"600000.SH": 1.0},
max_weight=max_weight,
gross_target=gross_target,
)
def test_sell_delta_respects_sellable(self):
deltas = order_deltas(
{"600000.XSHG": 0},
{"600000.XSHG": 1000},
{"600000.XSHG": 300},
lot_size=100,
)
self.assertEqual(deltas, {"600000.XSHG": -300})
def test_star_targets_and_partial_orders_respect_200_share_minimum(self):
self.assertEqual(
target_quantities(
{"688301.XSHG": 1.0},
{"688301.XSHG": 300.0},
equity=50_000,
lot_size=100,
cash_buffer=0.02,
),
{"688301.XSHG": 0},
)
self.assertEqual(
target_quantities(
{"688301.XSHG": 1.0},
{"688301.XSHG": 200.0},
equity=50_000,
lot_size=100,
cash_buffer=0.02,
),
{"688301.XSHG": 200},
)
self.assertEqual(
order_deltas(
{"688301.XSHG": 300},
{"688301.XSHG": 200},
{"688301.XSHG": 200},
lot_size=100,
),
{},
)
self.assertEqual(
order_deltas(
{"688301.XSHG": 1300},
{"688301.XSHG": 1400},
{"688301.XSHG": 1400},
lot_size=100,
),
{},
)
def test_complete_odd_lot_liquidation_is_preserved(self):
self.assertEqual(
order_deltas(
{"600000.XSHG": 0},
{"600000.XSHG": 1050},
{"600000.XSHG": 1050},
lot_size=100,
),
{"600000.XSHG": -1050},
)
self.assertEqual(
order_deltas(
{"688301.XSHG": 0},
{"688301.XSHG": 150},
{"688301.XSHG": 150},
lot_size=100,
),
{"688301.XSHG": -150},
)
def test_complete_plan_is_deterministic(self):
histories = {
"600000.SH": [10 + index * 0.1 for index in range(25)],
"000001.SZ": [10 + index * 0.05 for index in range(25)],
}
arguments = dict(
price_history=histories,
current={},
sellable={},
equity=100_000,
lookback=20,
skip=0,
top_n=2,
max_weight=0.5,
gross_target=0.95,
cash_buffer=0.02,
lot_size=100,
)
self.assertEqual(
build_rebalance_plan(**arguments),
build_rebalance_plan(**arguments),
)
if __name__ == "__main__":
unittest.main()