"""外部冻结EPS预期/公告时间、事件去重、真实给定会话与20期开盘账。""" from datetime import datetime from decimal import Decimal as D import json dates=['2026-01-05','2026-01-06','2026-01-07','2026-01-08','2026-01-09', '2026-01-12','2026-01-13','2026-01-14','2026-01-15','2026-01-16', '2026-01-20','2026-01-21','2026-01-22','2026-01-23','2026-01-26', '2026-01-27','2026-01-28','2026-01-29','2026-01-30','2026-02-02', '2026-02-03','2026-02-04'] sessions=[day+'T09:30:00-05:00' for day in dates] def unique_events(events): seen={} for event in events: key=event['event_id'] if key in seen and seen[key]!=event: raise ValueError('冲突事件版本需先外部冻结解析') seen[key]=event return list(seen.values()) def plan(event,opens=sessions): parsed=[datetime.fromisoformat(t) for t in opens] if parsed!=sorted(parsed) or len(set(parsed))!=len(parsed): raise ValueError('交易会话必须按时间唯一有序') announcement=datetime.fromisoformat(event['announcement']) frozen=datetime.fromisoformat(event['estimate_frozen']) available=datetime.fromisoformat(event['available']) if frozen>=announcement: return {'status':'late_expectation'} if availableavailable] if not eligible: return {'status':'no_entry_session','surprise':str(surprise)} entry=min(eligible,key=lambda i:datetime.fromisoformat(opens[i])) return {'status':'eligible','surprise':str(surprise),'entry':entry,'due':entry+20, 'entry_time':opens[entry]} def run(trade,opens=sessions): if trade['status']!='eligible': raise ValueError('ineligible_event') cash,quantity,fees,ledger=D(1000),0,0,[] for i,time in enumerate(opens): price=D(11) if i==20 else D('10.5') if i==21 else D(10) orders=[] if i==trade['entry']: cash-=40*price+1;quantity=40;fees+=1 orders.append(['buy',40,str(price),1]) if quantity and i==trade['due']: cash+=quantity*price-1;orders.append(['sell',quantity,str(price),1]) quantity=0;fees+=1 ledger.append({'time':time,'orders':orders,'quantity':quantity, 'cash':str(cash),'fees':fees,'equity':str(cash+quantity*price)}) return ledger event={'event_id':'ALFA:2025Q4:diluted_GAAP_USD','announcement':'2026-01-05T08:00:00-05:00', 'available':'2026-01-05T08:00:00-05:00','estimate_frozen':'2026-01-04T20:00:00-05:00', 'expected_eps':'1','actual_eps':'1.2','expected_basis':'diluted_GAAP_USD', 'actual_basis':'diluted_GAAP_USD'} assert len(unique_events([event,dict(event)]))==1 try: unique_events([event,dict(event,actual_eps='1.3')]) except ValueError: pass else: raise AssertionError('冲突修订不应当成第二事件或静默覆盖') pre=plan(event); ledger=run(pre) assert pre['surprise']=='0.2' and pre['entry']==0 and pre['due']==20 assert ledger[0]['orders']==[['buy',40,'10',1]] and ledger[0]['cash']=='599' assert ledger[20]['orders']==[['sell',40,'11',1]] assert D(ledger[-1]['cash'])==D(ledger[-1]['equity'])==D(1038) assert ledger[-1]['quantity']==0 and ledger[-1]['fees']==2 post_event=dict(event,announcement='2026-01-05T16:10:00-05:00',available='2026-01-05T16:10:00-05:00') post=plan(post_event); post_ledger=run(post) assert post['entry']==1 and post['due']==21 and post_ledger[-1]['cash']=='1018.0' assert post_ledger[1]['orders']==[['buy',40,'10',1]] and post_ledger[1]['cash']=='599' assert post_ledger[21]['orders']==[['sell',40,'10.5',1]] assert post_ledger[-1]['quantity']==0 and post_ledger[-1]['fees']==2 assert plan(dict(event,expected_eps='0'))['status']=='zero_denominator' assert plan(dict(event,estimate_frozen=event['announcement']))['status']=='late_expectation' assert plan(dict(event,actual_basis='adjusted_USD'))['status']=='basis_mismatch' assert plan(dict(event,actual_eps='1.1'))['status']=='eligible' assert plan(dict(event,actual_eps='1.099'))['status']=='below_threshold' assert plan(dict(event,actual_eps='NaN'))['status']=='nonfinite_eps' assert plan(dict(event,available='2026-01-05T07:59:00-05:00'))['status']=='invalid_availability' assert plan(event,sessions[:10])['entry']==pre['entry'] assert run(plan(event,sessions[:10]),sessions[:10])==ledger[:10] print(json.dumps({'frozen_input':event,'pre_market_plan':pre,'pre_entry':ledger[0], 'pre_exit':ledger[20],'post_market_plan':post,'post_exit':post_ledger[21], 'duplicate_events':1,'scope':'synthetic EPS/expectation inputs; supplied real session dates, no historical expectations service'}))