From 41c3de31a39fb10e98919ea8408ed52f514e635f Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Thu, 16 Jul 2026 00:45:43 +0800 Subject: [PATCH 1/2] feat: remove derived sizing contract state Co-Authored-By: Codex --- .../position_sizing_contract_v1.py | 118 ++++++++++++++++++ tests/test_position_sizing_contract_v1.py | 21 ++++ 2 files changed, 139 insertions(+) create mode 100644 src/quant_platform_kit/position_sizing_contract_v1.py create mode 100644 tests/test_position_sizing_contract_v1.py diff --git a/src/quant_platform_kit/position_sizing_contract_v1.py b/src/quant_platform_kit/position_sizing_contract_v1.py new file mode 100644 index 0000000..e96a51b --- /dev/null +++ b/src/quant_platform_kit/position_sizing_contract_v1.py @@ -0,0 +1,118 @@ +"""Canonical immutable raw position-sizing contract; no sizing logic.""" +from __future__ import annotations +import hashlib +import json +import math +import re +from dataclasses import dataclass +from datetime import date +_DATE=re.compile(r'^\d{4}-\d{2}-\d{2}$'); _ID=re.compile(r'^[A-Za-z0-9._:-]{1,128}$'); _SAFE=2**53-1 +class PositionSizingContractError(ValueError): pass +def _fail(): raise PositionSizingContractError('invalid position sizing contract') +def _str(v): + if type(v) is not str or not v or len(v)>256 or not v.isprintable(): _fail() + return v +def _id(v): + v=_str(v) + if not _ID.fullmatch(v): _fail() + return v +def _num(v,lo=0.,hi=1.): + if type(v) is int: + if abs(v)>_SAFE: _fail() + elif type(v) is not float: _fail() + if not math.isfinite(v): _fail() + try: out=float(v) + except (OverflowError,ValueError): _fail() + if out==0.0: return 0.0 + if not lo<=out<=hi: _fail() + return out +def _date(v): + v=_str(v) + if not _DATE.fullmatch(v): _fail() + try: parsed=date.fromisoformat(v) + except ValueError: _fail() + if parsed.isoformat()!=v: _fail() + return v +def _dict(v,keys): + if type(v) is not dict or set(v)!=set(keys): _fail() + return v +def _bytes(v): + try:return json.dumps(v,ensure_ascii=True,sort_keys=True,separators=(',',':'),allow_nan=False).encode('ascii') + except (TypeError,ValueError,UnicodeError): _fail() +@dataclass(frozen=True,slots=True) +class Target: + symbol:str; raw_weight:float + @classmethod + def parse(cls,v): + d=_dict(v,('symbol','raw_weight')); return cls(_id(d['symbol']),_num(d['raw_weight'],-1,1)) + def wire(self): return {'raw_weight':self.raw_weight,'symbol':self.symbol} +@dataclass(frozen=True,slots=True) +class Evidence: + package_id:str; scope:str; as_of:str; valid_until:str; digest:str; sample_count:int + @classmethod + def parse(cls,v): + d=_dict(v,('package_id','scope','as_of','valid_until','digest','sample_count')); a=_date(d['as_of']); u=_date(d['valid_until']) + if u Date: Thu, 16 Jul 2026 00:54:40 +0800 Subject: [PATCH 2/2] fix: keep sizing contract policy agnostic Co-Authored-By: Codex --- .../position_sizing_contract_v1.py | 15 +++++++-------- tests/test_position_sizing_contract_v1.py | 3 +++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/quant_platform_kit/position_sizing_contract_v1.py b/src/quant_platform_kit/position_sizing_contract_v1.py index e96a51b..f0bafd5 100644 --- a/src/quant_platform_kit/position_sizing_contract_v1.py +++ b/src/quant_platform_kit/position_sizing_contract_v1.py @@ -16,7 +16,7 @@ def _id(v): v=_str(v) if not _ID.fullmatch(v): _fail() return v -def _num(v,lo=0.,hi=1.): +def _num(v,lo=None,hi=None): if type(v) is int: if abs(v)>_SAFE: _fail() elif type(v) is not float: _fail() @@ -24,7 +24,7 @@ def _num(v,lo=0.,hi=1.): try: out=float(v) except (OverflowError,ValueError): _fail() if out==0.0: return 0.0 - if not lo<=out<=hi: _fail() + if lo is not None and outhi: _fail() return out def _date(v): v=_str(v) @@ -44,7 +44,7 @@ class Target: symbol:str; raw_weight:float @classmethod def parse(cls,v): - d=_dict(v,('symbol','raw_weight')); return cls(_id(d['symbol']),_num(d['raw_weight'],-1,1)) + d=_dict(v,('symbol','raw_weight')); return cls(_id(d['symbol']),_num(d['raw_weight'])) def wire(self): return {'raw_weight':self.raw_weight,'symbol':self.symbol} @dataclass(frozen=True,slots=True) class Evidence: @@ -68,8 +68,8 @@ class Authorization: @classmethod def parse(cls,v): d=_dict(v,('position_control_allowed','consumption_evidence_status','bounded_budget','expires_at')) - if type(d['position_control_allowed']) is not bool or d['position_control_allowed'] is not True or d['consumption_evidence_status']!='automation_approved': _fail() - return cls(True,d['consumption_evidence_status'],_num(d['bounded_budget']),_date(d['expires_at'])) + if type(d['position_control_allowed']) is not bool: _fail() + return cls(d['position_control_allowed'],_id(d['consumption_evidence_status']),_num(d['bounded_budget']),_date(d['expires_at'])) def wire(self): return {'bounded_budget':self.bounded_budget,'consumption_evidence_status':self.consumption_evidence_status,'expires_at':self.expires_at,'position_control_allowed':self.position_control_allowed} @dataclass(frozen=True,slots=True) class Policy: @@ -77,8 +77,7 @@ class Policy: @classmethod def parse(cls,v): d=_dict(v,('fractional_kelly','total_exposure_cap','cash_reserve','risk_scalar')) - if d['fractional_kelly'] not in (0.25,0.5): _fail() - return cls(_num(d['fractional_kelly'],0,.5),_num(d['total_exposure_cap']),_num(d['cash_reserve']),_num(d['risk_scalar'])) + return cls(_num(d['fractional_kelly']),_num(d['total_exposure_cap']),_num(d['cash_reserve']),_num(d['risk_scalar'])) def wire(self): return {'cash_reserve':self.cash_reserve,'fractional_kelly':self.fractional_kelly,'risk_scalar':self.risk_scalar,'total_exposure_cap':self.total_exposure_cap} def _sort(xs): return tuple(sorted(xs,key=lambda x:tuple(x.wire().items()))) @@ -108,7 +107,7 @@ def _build(as_of,targets,evidence,caps,authorization,policy,risk_route): a=_date(as_of) if type(targets) not in (tuple,list) or type(evidence) not in (tuple,list) or type(caps) not in (tuple,list): _fail() ts=_sort(tuple(Target.parse(v) for v in targets)); es=_sort(tuple(Evidence.parse(v) for v in evidence)); cs=_sort(tuple(Caps.parse(v) for v in caps)) - if not es or any(e.as_of!=a or e.valid_until