"""C05基金运营构造算例;Python 3.10+标准库,无网络和仓库依赖。""" from decimal import Decimal, ROUND_HALF_UP, ROUND_DOWN, getcontext from pathlib import Path import argparse import json getcontext().prec = 40 D = Decimal def cents(x): return D(x).quantize(D('0.01'), rounding=ROUND_HALF_UP) def down(x): return D(x).quantize(D('0.01'), rounding=ROUND_DOWN) def allocate(requests, cap): if not requests or sum(requests)<=0 or cap<0 or any(x<0 for x in requests): raise ValueError('申请总量须为正,申请及额度不可为负') available=min(cap,sum(requests));ratio=D(available)/D(sum(requests)) exact=[D(x)*ratio for x in requests];floor=[int(x) for x in exact] left=available-sum(floor) rank=sorted(range(len(requests)),key=lambda i:(-(exact[i]-floor[i]),i)) bonus=[int(i in rank[:left]) for i in range(len(requests))] return ratio,exact,floor,bonus,[floor[i]+bonus[i] for i in range(len(requests))] def rejected(call): try:call() except ValueError:return True return False def unit_split(quantity, unit): if quantity<0 or unit<=0: raise ValueError('份额须非负,单位须为正整数') return divmod(quantity,unit) def pack(inputs, tables, summary, contrast, checks, precision): assert all(checks.values()), checks return {'性质':'匿名教学构造,非真实产品、历史清单或真实交易', '精度与单位':precision, '输入':inputs,'表格':tables,'汇总':summary,'条件对照':contrast,'自检':checks} def subscription(): inputs = [ {'编号':'R1','申请金额':D('10000'),'退款':D('0'),'收费类型':'比例','费率':D('.012'),'固定费':D('0'),'有效天数标签':10,'登记利息':D('2.347')}, {'编号':'R2','申请金额':D('25000'),'退款':D('0'),'收费类型':'固定','费率':D('0'),'固定费':D('50'),'有效天数标签':20,'登记利息':D('7.009')}, {'编号':'R3','申请金额':D('3000'),'退款':D('0'),'收费类型':'零费','费率':D('0'),'固定费':D('0'),'有效天数标签':1,'登记利息':D('.007')}, ] rows=[] for x in inputs: eligible=x['申请金额']-x['退款'] principal=cents(eligible/(1+x['费率'])) if x['收费类型']=='比例' else eligible-x['固定费'] fee=eligible-principal interest=down(x['登记利息']) rows.append({'编号':x['编号'],'本金':principal,'费用':fee,'登记利息':x['登记利息'],'利息份额':interest,'本金份额':principal,'确认总份额':principal+interest,'退款':x['退款'],'利息截位余额':x['登记利息']-interest}) return pack({'面值元每份':D('1'),'申请':inputs,'边界':'本金与利息分栏;天数只为凭证标签,不由天数猜计息率'},rows, {'申请总额':sum(x['申请金额'] for x in inputs),'本金合计':sum(x['本金'] for x in rows),'费用合计':sum(x['费用'] for x in rows),'利息份额合计':sum(x['利息份额'] for x in rows),'利息截位余额合计':sum(x['利息截位余额'] for x in rows),'确认总份额':sum(x['确认总份额'] for x in rows),'登记利息合计':sum(x['登记利息'] for x in inputs)}, {'R1错按申请额直接乘费率':inputs[0]['申请金额']*inputs[0]['费率'],'R1正确费':rows[0]['费用'],'先合并再截利息份额':down(sum(x['登记利息'] for x in inputs)),'逐笔截位与合并截位差':down(sum(x['登记利息'] for x in inputs))-sum(x['利息份额'] for x in rows),'R3错误四舍五入利息份额':cents('.007'),'R3正确利息份额':down('.007'),'失败分支':{'申请':D('3000'),'费用':D('0'),'本金':D('0'),'退款':D('3000'),'确认份额':D('0')}}, {'逐笔资金闭合':all(i['申请金额']==r['本金']+r['费用']+r['退款'] for i,r in zip(inputs,rows)),'利息保留截位余额':all(r['登记利息']==r['利息份额']+r['利息截位余额'] for r in rows),'零利息':down(0)==0,'小于一分利息':down('.007')==0}, '金额元;本金按外扣后四舍五入到分;面值1元,本金份额两位、利息份额截两位;登记利息保留三位,截位余额不虚记退款。') def proportional(): requests=[1000,2000,3000,4000];cap=6001;total=sum(requests) ratio,exact,floor,bonus,confirmed=allocate(requests,cap);left=cap-sum(floor) rows=[{'申请人':chr(65+i),'申请份额':q,'精确配额':exact[i],'向下整数':floor[i],'补余份':bonus[i],'确认份额':floor[i]+bonus[i],'实付本金元':D(floor[i]+bonus[i]),'退款元':D(q-floor[i]-bonus[i])} for i,q in enumerate(requests)] return pack({'面值':D('1'),'有效申请份额':requests,'募集剩余额度份':cap,'费用元':D('0'),'利息元':D('0'),'教学余份政策':'先取整数,再按小数余数降序;同余按A至D顺序,仅为本实验政策'},rows, {'总申请':total,'比例':ratio,'整数合计':sum(floor),'待分余份':left,'确认合计':sum(x['确认份额'] for x in rows),'退款合计':sum(x['退款元'] for x in rows)}, {'全额确认为错误':{'确认份额':total,'超出额度':total-cap},'只舍不分余份':sum(floor),'零额度确认':sum(allocate(requests,0)[4]),'额度覆盖全部申请确认':sum(allocate(requests,total+1000)[4])}, {'全体恰到教学额度':sum(x['确认份额'] for x in rows)==cap,'个人款份闭合':all(D(x['申请份额'])==x['实付本金元']+x['退款元'] for x in rows),'余份分配合法':left>=0 and left<4,'零申请拒绝除零':rejected(lambda:allocate([0,0],6001)),'零额度确认零':sum(allocate(requests,0)[4])==0,'未超额不创造份额':allocate(requests,total+1)[4]==requests,'同余按编号':allocate([1,1],1)[4]==[1,0]}, '数量份为整数;中间配额十进制完整保留;金额元,面值1、无费用利息;不把此分配政策当真实登记规则。') def deferral(): inputs=[('甲',1500,1000,False),('乙',900,600,False),('丙',500,400,True)] rows=[] for name,holding,request,cancel in inputs: first=D(request)*D('.4');pending=D(request)-first;cancelled=pending if cancel else D(0) second=(pending-cancelled)*D('.5');remain=pending-cancelled-second rows.append({'持有人':name,'原持有':holding,'原申请':request,'第一日确认':first,'第一日毛款':first*D('1.20'),'第一日后待办':pending-cancelled,'撤销未办':cancelled,'第二日确认':second,'第二日毛款':second*D('1.10'),'两日后待办':remain,'期末仍持份额':D(holding)-first-second,'合计毛款':first*D('1.20')+second*D('1.10')}) return pack({'持有及申请':[{'持有人':n,'持有':h,'申请':q,'未办选择撤销':c} for n,h,q,c in inputs],'第一日比例':D('.4'),'第二日对顺延量比例':D('.5'),'第一日净值':D('1.20'),'第二日净值':D('1.10'),'费用':D('0'),'日标签':'构造开放日D1、D2,非实际承诺'},rows, {'原持有合计':sum(x['原持有'] for x in rows),'原申请合计':sum(x['原申请'] for x in rows),'第一日确认合计':sum(x['第一日确认'] for x in rows),'第二日确认合计':sum(x['第二日确认'] for x in rows),'第一日顺延合计':sum(x['第一日后待办'] for x in rows),'第一日毛款合计':sum(x['第一日毛款'] for x in rows),'第二日毛款合计':sum(x['第二日毛款'] for x in rows),'期末仍持合计':sum(x['期末仍持份额'] for x in rows),'确认份额合计':sum(x['第一日确认']+x['第二日确认'] for x in rows),'待办合计':sum(x['两日后待办'] for x in rows),'撤销合计':sum(x['撤销未办'] for x in rows),'毛款合计':sum(x['合计毛款'] for x in rows)}, {'甲全部原申请错用首日净值':D('1200'),'甲只对实际两日确认错用首日净值':D('840'),'甲正确两日毛款':rows[0]['合计毛款'],'第二日比例为零甲待办':D('600'),'第二日比例为一甲待办':D('0')}, {'申请状态守恒':all(D(x['原申请'])==x['第一日确认']+x['第二日确认']+x['两日后待办']+x['撤销未办'] for x in rows),'持仓只扣确认':all(D(x['原持有'])==x['第一日确认']+x['第二日确认']+x['期末仍持份额'] for x in rows),'零确认不生款':D(0)*D('1.20')==0,'待办不超仍持':all(x['两日后待办']<=x['期末仍持份额'] for x in rows)}, '份额份、净值元每份、款元;全为有限十进制,零费用;待办不是应收现金,已确认尚未支付另建应收款。') def transfer(): states=[('E0','起始',8000,0,0,2000),('T1','场内转场外有效申请锁定',5000,3000,0,2000),('T1','成功登记完成',5000,0,0,5000),('T2','场外转场内已记减待接收',5000,0,2000,3000),('T2','失败恢复原场外记录',5000,0,0,5000)] rows=[{'事件编号':e,'截点':s,'场内可用':a,'场内锁定':b,'独占在途':c,'场外可用':d,'实有总份额':a+b+c+d} for e,s,a,b,c,d in states] return pack({'起始场内':8000,'起始场外':2000,'T1数量':3000,'T1结果':'成功','T2数量':2000,'T2结果':'失败,构造恢复凭证齐全','在途定义':'仅在转出已记减且接收尚未成功登记时单列,和锁定互斥'},rows, {'唯一实有份额':10000,'最终场内':5000,'最终场外':5000}, {'成功后仍用旧场内8000加新场外5000':13000,'重复计入':3000,'锁定3000再加在途3000的错误总数':13000,'零数量申请':'拒绝;上海原文要求大于0整数份'}, {'所有截点守恒':all(x['实有总份额']==10000 for x in rows),'锁定在途互斥':all(not(x['场内锁定'] and x['独占在途']) for x in rows),'失败恢复非新增':rows[-1]['场外可用']==5000,'每事件唯一':len({x['事件编号'] for x in rows})==3}, '单位份,整数;迁移数量不因净值改变;流程只作上海LOF相应机制的匿名状态示范,不推深市或承诺时限。') def sidepocket(): initial=[('甲',600,100,D(0)),('乙',400,0,D(0)),('丙',0,0,D('80'))] main_assets=D('800');base=sum(x[1] for x in initial);nav=main_assets/base gross=D('150');cost=D('10');net=gross-cost;rate=net/base rows=[] for name,old,redeem,subscription_cash in initial: added=subscription_cash/nav rows.append({'持有人':name,'启用前份额':old,'主袋初始份额':old,'侧袋确认份额':old,'主袋赎回份额':redeem,'主袋赎回款':D(redeem)*nav,'后申购份额':added,'主袋期末份额':D(old)-redeem+added,'侧袋分配款':D(old)*rate}) return pack({'原总份额':1000,'分离后主袋可估资产元':D('800'),'特定资产历史账面标签元':D('200'),'侧袋当前可靠估值':None,'主袋净值':D('.8'),'丙后申购元':D('80'),'后续已变现构造毛款':D('150'),'变现后列支构造费用':D('10'),'侧袋剩余可回收':None},rows, {'侧袋净分配':net,'每侧袋份额分配元':rate,'主袋期末资产':main_assets-sum(x['主袋赎回款'] for x in rows)+sum(x[3] for x in initial),'主袋期末份额':sum(x['主袋期末份额'] for x in rows),'启用当日主侧袋合计当前价值':None}, {'错把历史200当保证回收甲应收':D('120'),'实际构造该次甲收到':D('84'),'错误把后来丙纳入侧袋分母':1100,'正确侧袋分母':1000,'零变现分支':'已分现金零,侧袋权利仍在,剩余回收未知'}, {'侧袋只归原持有人':sum(x['侧袋确认份额'] for x in rows)==1000 and rows[2]['侧袋确认份额']==0,'分款守恒':sum(x['侧袋分配款'] for x in rows)==D('140'),'主袋份额链':sum(x['主袋期末份额'] for x in rows)==1000,'主袋资产链':D('800')-D('80')+D('80')==D('800')}, '份额份、金额元、净值元每份;主袋与侧袋分别核对,未知值为null;140是后续构造已回收净额,不是启用日预测。') def liquidation(): base=D('100000');personal=D('1000');share=personal/base cash=D('80000');receivable=D('20000');debt=D('5000');cost=D('2000');tax=D('1000');recovery=D('18000');new_cost=D('500') deductions=debt+cost+tax;initial_net=cash+receivable-deductions first=cash-deductions;second=recovery-new_cost;distributed=first+second rows=[{'阶段':'起始可辨认账面','现金':cash,'应收账面':receivable,'本期回收':D('0'),'费用税债':deductions,'本期可分':D('0'),'累计已分':D('0'),'可辨认未分账面':initial_net,'每份本期分配':D('0'),'个人本期到账':D('0')}, {'阶段':'第一次分配','现金':cash,'应收账面':receivable,'本期回收':D('0'),'费用税债':deductions,'本期可分':first,'累计已分':first,'可辨认未分账面':receivable,'每份本期分配':first/base,'个人本期到账':first/base*personal}, {'阶段':'第二次回收并分配','现金':recovery,'应收账面':D('0'),'本期回收':recovery,'费用税债':new_cost,'本期可分':second,'累计已分':distributed,'可辨认未分账面':D('0'),'每份本期分配':second/base,'个人本期到账':second/base*personal}] return pack({'总基准份额':base,'个人基准份额':personal,'起始现金元':D('80000'),'起始应收账面元':D('20000'),'应付债务元':D('5000'),'费用元':D('2000'),'税元':D('1000'),'第二期实际回收元':D('18000'),'第二期新费用元':D('500'),'额外争议权利回收金额':None,'分配精度':'每份保留本例所需三位,再乘个人份额,金额到分;仅本实验'},rows, {'起始可辨认资产账面':cash+receivable,'已知扣除合计':deductions,'个人占比':share,'起始可辨认净账面':initial_net,'个人起始净账面':initial_net*share,'实际分配合计':distributed,'每份累计分配':distributed/base,'回收减记':receivable-recovery,'个人回收减记':(receivable-recovery)*share,'新增费用':new_cost,'个人新增费用':new_cost*share,'个人累计到账':distributed*share,'个人相对起始净账面减少':(initial_net-distributed)*share,'额外未知权利不并入总计':None}, {'错用最后净值1元推个人保证款':D('1000'),'实际构造分配':D('895'),'只记第一期漏款':D('175'),'回收若为0且新费用为0第二次分配':D('0')}, {'净额瀑布':D('100000')-D('5000')-D('2000')-D('1000')==D('92000'),'最终金额桥接':D('92000')-D('2000')-D('500')==D('89500'),'按份比例':D('89500')*share==D('895'),'一期已分加待分':D('72000')+D('20000')==D('92000')}, '金额元,份额份;每份分配元每份;应收账面不是保证回收,剩余未知权利null,不能强行令未知款为零。') def calendar(): raw=[('2026-11-02',True,True,None,None,'14:00'),('2026-11-03',True,True,False,None,'14:00'),('2026-11-04',True,False,None,None,'14:00'),('2026-11-05',True,True,None,False,'14:00'),('2026-11-06',True,None,None,None,'14:00'),('2026-11-07',False,False,None,None,'14:00'),('2026-11-08',False,False,None,None,'14:00'),('2026-11-09',True,True,None,None,'15:01'),('2026-11-10',True,True,None,None,'15:00'),('2026-11-11',True,True,None,None,'14:00')] def allowed(dom,foreign,override): if not dom or foreign is False or override is False:return False if foreign is None:return None return True rows=[] for day,dom,foreign,buy,redeem,time in raw: b=allowed(dom,foreign,buy);r=allowed(dom,foreign,redeem) rows.append({'日期':day,'境内开市':dom,'境外业务日':foreign,'申购公告覆盖':buy,'赎回公告覆盖':redeem,'提交时刻':time,'截点': '15:00','申购日开关':b,'赎回日开关':r,'申购本日受理':b if time<='15:00' else False,'赎回本日受理':r if time<='15:00' else False}) for i,x in enumerate(rows): for key in ['申购','赎回']: x[key+'下一候选日']=next((y['日期'] for j,y in enumerate(rows) if j>=i and y[key+'日开关'] is True and (j>i or x['提交时刻']<='15:00')),None) return pack({'样本':'十个日期标签全部为人为开关,不是真实2026年业务日历','条件':'本模型同时要求境内、境外为真,逐业务暂停优先;缺信息保留未知;截点含15:00','日历原始行':[dict(zip(['日期','境内','境外','申购覆盖','赎回覆盖','提交时间'],r)) for r in raw]},rows, {'状态语义':'True为满足本实验受理条件,False为不满足,null为待核;候选日不承诺确认到账','未知日期':'2026-11-06'}, {'只看境内开市会误判':'2026-11-04','只看统一恢复会漏赎回暂停':'2026-11-05','晚于截点下一候选':'2026-11-10','等于截点':'2026-11-10本日满足本实验'}, {'暂停优先':rows[1]['申购本日受理'] is False and rows[1]['赎回本日受理'] is True,'境外关闭':rows[2]['申购本日受理'] is False,'未知不当开放':rows[4]['申购本日受理'] is None,'截点边界':rows[7]['申购本日受理'] is False and rows[8]['申购本日受理'] is True,'十个日期':len(rows)==10}, '日期ISO标签,时刻为同一教学时区HH:MM;布尔开关非真实日历;无金额运算;候选日只从表中已知开放日期找。') def aum(): s0=D('1000');s1=D('1200');n0=D('1');n1=D('1.1') events=[{'事件':'期中申购','份额变化':D('300'),'事件净值':D('1.05'),'净流入':D('315')},{'事件':'期中赎回','份额变化':D('-100'),'事件净值':D('1.08'),'净流入':D('-108')}] for x in events:x['净流入']=x['份额变化']*x['事件净值'] endpoint=[{'分项':'原份额价格变化','公式':'S0×ΔN','金额':s0*(n1-n0)},{'分项':'按初始净值的份额变化','公式':'ΔS×N0','金额':(s1-s0)*n0},{'分项':'交叉项','公式':'ΔS×ΔN','金额':(s1-s0)*(n1-n0)}] return pack({'期初份额':s0,'期末份额':s1,'期初净值':n0,'期末净值':n1,'无费用分红拆并份额':True,'事件':events},{'二维端点分解':endpoint,'实际流量':events}, {'期初规模':s0*n0,'期末规模':s1*n1,'规模增长金额':s1*n1-s0*n0,'规模增长比例':s1*n1/(s0*n0)-1,'净值增长比例':n1/n0-1,'实际净流入':sum(x['净流入'] for x in events),'实际投资损益金额':s1*n1-s0*n0-sum(x['净流入'] for x in events)}, {'端点份额差乘期末净值':(s1-s0)*n1,'比实际净流入高':(s1-s0)*n1-sum(x['净流入'] for x in events),'相同端点另一流量路径':{'申购300份净值':D('1.02'),'申购流入':D(300)*D('1.02'),'赎回100份净值':D('1.09'),'赎回流出':D(100)*D('1.09'),'净流入':D(300)*D('1.02')-D(100)*D('1.09'),'投资损益':s1*n1-s0*n0-(D(300)*D('1.02')-D(100)*D('1.09'))},'固定份额零变化分支':{'份额变化项':D(0),'交叉项':D(0),'规模价格项':s0*(n1-n0)},'份额与净值端点都不变但有流量':{'初末份额':1000,'初末净值':D('1'),'申购份额':100,'申购净值':D('1'),'赎回份额':100,'赎回净值':D('1.2'),'申购流入':D(100)*D('1'),'赎回流出':D(100)*D('1.2'),'净流入':D(100)*(D('1')-D('1.2')),'投资损益':-D(100)*(D('1')-D('1.2'))}}, {'二维恒等式':sum(x['金额'] for x in endpoint)==D('320'),'事件份额链':s0+sum(x['份额变化'] for x in events)==s1,'流量金额闭合':D('1000')+D('207')+D('113')==D('1320'),'另一路径闭合':D('1000')+D('197')+D('123')==D('1320')}, '规模与流量元、份额份、净值元每份;十进制恒等式;端点分项是归因约定,不把交叉项自动命名真实净流入。') def substitution(): specs=[('甲','沪市','禁止现金替代',1000,D('10'),1000,D('0'),None,D('0'),None),('乙','非沪市','允许现金替代',2000,D('5'),0,D('.10'),D('5.2'),D('20'),None),('丙','沪市','必须现金替代',500,D('8'),0,D('0'),None,D('0'),D('4000'))] rows=[] for name,market,flag,quantity,reference,delivered,premium,buy_price,fee,fixed in specs: substitute=quantity-delivered;ref_amount=D(substitute)*reference prepaid=cents(ref_amount*(1+premium)) bought=D(substitute)*buy_price if buy_price is not None else None final=cents(bought+fee) if bought is not None else (fixed if fixed is not None else D(0)) refund=max(prepaid-final,D(0));supplement=max(final-prepaid,D(0)) rows.append({'成份券':name,'挂牌市场':market,'模式':'实物','标志':flag,'篮子数量':quantity,'参考价':reference,'本次交券':delivered,'替代数量':substitute,'参考替代金额':ref_amount,'构造预收比例':premium,'预收':prepaid,'代买金额':bought,'实际费用':fee,'最终替代成本':final,'退款':refund,'补款':supplement}) alternate=D(specs[1][3])*D('5.6')+specs[1][8] return pack({'篮子':'匿名构造单篮子,非B-S26入口历史清单','原始券记录':[dict(zip(['券','市场','标志','篮子量','参考价','交券量','预收比例','实际代买价','费用','固定替代额'],x)) for x in specs],'模式':'实物','丙规则':'本实验另定固定替代金额4000元,不借必须标志推导普遍退补规则','乙代买成交价':D('5.2'),'乙实际费用元':D('20'),'现金差额另核':D('0')},rows, {'参考替代金额合计':sum(x['参考替代金额'] for x in rows),'预收合计':sum(x['预收'] for x in rows),'最终替代成本':sum(x['最终替代成本'] for x in rows),'退款合计':sum(x['退款'] for x in rows),'补款合计':sum(x['补款'] for x in rows),'甲交证券参考估值':D(specs[0][5])*specs[0][4],'仅乙实际费用':specs[1][8]}, {'乙代买价改为5.6且费用20':{'最终成本':alternate,'预收':rows[1]['预收'],'补款':max(alternate-rows[1]['预收'],D(0)),'退款':max(rows[1]['预收']-alternate,D(0))},'错把乙溢价1000全当费用':rows[1]['预收']-rows[1]['参考替代金额'],'再加实际费用的错误费用合计':rows[1]['预收']-rows[1]['参考替代金额']+rows[1]['实际费用'],'乙本例实际费用':rows[1]['实际费用'],'乙若实际成本恰等预收':{'退款':D('0'),'补款':D('0')},'实物沪市允许标志分支':'申购优先交券,不足现金;赎回该券不允许现金替代。现金模式或非沪市允许标志另按公告含义核。'}, {'逐券现金闭合':all(x['预收']+x['补款']-x['退款']==x['最终替代成本'] for x in rows),'证券数量':all(x['本次交券']+x['替代数量']==x['篮子数量'] for x in rows),'退款补款不同时正':all(not(x['退款']>0 and x['补款']>0) for x in rows),'反例补款闭合':D('11000')+D('220')==D('11220')}, '证券数量份额单位为股(仅本例),金额元;预收比例是构造占款条件;代买金额加费用为乙最终成本,丙固定金额不能混同代买金额。') def receipt(): specs=[('证券甲',1000,D('20'),1000,D('19.8'),D('10')),('证券乙',500,D('30'),500,D('30.4'),D('8'))] original=65000;cancel=50000;cash=D('14000')+D('1000');rows=[] for name,received,reference,sold,price,fee in specs: rows.append({'资产':name,'收到数量':received,'接收参考价':reference,'接收估值':D(received)*reference,'后来卖出数量':sold,'后来成交价':price,'卖出毛款':D(sold)*price,'卖出费用':fee,'卖出净款':D(sold)*price-fee,'期末余券':received-sold,'接收至卖出价格影响':D(sold)*(price-reference)}) value=sum(x['接收估值'] for x in rows);net=sum(x['卖出净款'] for x in rows) return pack({'赎回前ETF份额':65000,'最小赎回单位':50000,'本次注销':50000,'接收替代现金':D('14000'),'接收现金差额':D('1000'),'赎回环节其他费用':D('0'),'证券明细输入':[{'资产':x['资产'],'数量':x['收到数量'],'接收价':x['接收参考价'],'后来卖出价':x['后来成交价'],'卖出费用':x['卖出费用']} for x in rows]},rows, {'剩余ETF份额':original-cancel,'接收现金':cash,'接收证券估值':value,'接收对价估值合计':value+cash,'卖出毛款合计':sum(x['卖出毛款'] for x in rows),'卖出费用合计':sum(x['卖出费用'] for x in rows),'后来证券净变现':net,'后来全部现金':net+cash,'接收估值到净变现差':net-value}, {'只看现金误报对价短缺':value,'接收估值加最终变现重复合计':value+net+cash,'证券未售分支':{'现金':cash,'证券估值':value,'二者合计':value+cash},'不改变接收数量的价格变化':'后来卖出价改变只影响变现金额,不追改最初收到的股数'}, {'ETF份额守恒':65000-50000==15000,'每券数量守恒':all(x['收到数量']==x['后来卖出数量']+x['期末余券'] for x in rows),'接收账闭合':sum(x['接收估值'] for x in rows)+D('15000')==D('50000'),'变现账闭合':sum(x['卖出净款'] for x in rows)+D('15000')==D('49982'),'变现差来自价格与费用':D('-200')+D('200')-D('18')==D('-18')}, 'ETF份额份、证券股数股、价元每股、金额元;接收估值不等于保证卖出价;剩余ETF15000份另估值,不混入本次注销对价。') def units(): holdings=[12400,50000,123450];basket=50000;lot=100 rows=[] for h in holdings: q,r=unit_split(h,basket);hands,odd=unit_split(h,lot);q2,r2=unit_split(h,60000) rows.append({'持有份额':h,'每手份额':lot,'完整手数':hands,'不足一手余份':odd,'一级单位份额':basket,'算术整篮子数':q,'一级余份':r,'单位改为60000后的整篮子':q2,'单位改为60000后的余份':r2}) return pack({'二级每手份额':lot,'一级单位份额':basket,'单位调整后份额':60000,'三种持仓':holdings,'可用状态分支':{'总持有':50000,'锁定':100,'可用':49900}},rows, {'两类数量单位比例':basket//lot,'锁定分支可用整篮子':unit_split(50000-100,basket)[0],'总持有为零整篮子':unit_split(0,basket)[0]}, {'误把123450份直接除100的1234.5手当一级篮子':D('1234.5'),'实际算术一级篮子':2,'锁定分支只看总持有会误判':'总份额50000但可用49900,不满足本例50000的数量门;还须核准入和对价','不足一手余份':'只报告余数,不据此给通用品种的零碎份额申报规则'}, {'一级整除恒等式':all(x['算术整篮子数']*basket+x['一级余份']==x['持有份额'] for x in rows),'二级整数分拆':all(x['完整手数']*lot+x['不足一手余份']==x['持有份额'] for x in rows),'调整后恒等式':all(x['单位改为60000后的整篮子']*60000+x['单位改为60000后的余份']==x['持有份额'] for x in rows),'余数界限':all(0<=x['一级余份']