"""R646:USD/HKD/CNY资格分账,FX只展示,不建立混币种交易账。""" from decimal import Decimal as D SUPPORTED={'USD','HKD','CNY'} def pool(currency,winners,initial,qty,price,fee,mark): if currency not in SUPPORTED or type(winners) is not int or winners<0:raise ValueError('unknown currency or count') if winners<5:return {'currency':currency,'status':'waiting_eligibility','NAV':None,'cash':None,'shares':None} initial,price,fee,mark=map(lambda x:D(str(x)),[initial,price,fee,mark]) if any(not x.is_finite() for x in [initial,price,fee,mark]) or initial<=0 or price<=0 or mark<=0 or fee<0 or type(qty) is not int or qty<0:raise ValueError('invalid pool inputs') cash=initial-qty*price-fee if cash<0:raise ValueError('unfunded pool') assert cash+qty*price==initial-fee nav=cash+qty*mark return {'currency':currency,'status':'active','initial':initial,'cash':cash,'shares':qty,'NAV':nav,'return':nav/initial-1} def native_sum(rows): active=[r for r in rows if r['status']=='active'] if len({r['currency'] for r in active})>1:raise ValueError('cross-currency native aggregation') return sum((r['NAV'] for r in active),D(0)) def display(rows,rates): active=[r for r in rows if r['status']=='active'] if any(r['currency'] not in rates for r in active):return {'status':'FX_unknown','USD_value':None} values={c:D(str(v)) for c,v in rates.items()} if any(c not in SUPPORTED or not v.is_finite() or v<=0 for c,v in values.items()):raise ValueError('invalid FX metadata') if 'USD' in values and values['USD']!=1:raise ValueError('USD numeraire must equal one') return {'status':'display_only','USD_value':sum((r['NAV']*values[r['currency']] for r in active),D(0))} rows=[pool('USD',5,1000,2,100,1,110),pool('HKD',4,None,0,None,None,None),pool('CNY',5,2000,10,20,2,21)] assert rows[0]['NAV']==D(1019) and rows[0]['return']==D('.019') assert rows[1]['status']=='waiting_eligibility' and rows[1]['cash'] is None assert rows[2]['NAV']==D(2008) and rows[2]['return']==D('.004') assert display(rows,{'USD':1,'CNY':'.14'})=={'status':'display_only','USD_value':D('1300.12')} assert display(rows,{'USD':1})['status']=='FX_unknown' try:native_sum(rows) except ValueError:pass else:raise AssertionError('unconverted NAVs added') for currency in ['EUR','UNKNOWN',None,'']: try:pool(currency,5,1000,1,100,1,110) except ValueError:pass else:raise AssertionError('unknown currency treated as valid pool') try:display(rows,{'USD':1,'CNY':'NaN'}) except ValueError:pass else:raise AssertionError('nonfinite FX displayed') print('USD cash=799 shares=2 NAV=1019 return=1.9% CNY cash=1798 shares=10 NAV=2008 return=0.4%') print('HKD winners=4 status=waiting_eligibility capital_not_created=True synthetic_CNY_to_USD=0.14 display_USD=1300.12') print('native_cross_currency_sum=rejected missing_FX=unknown display_is_not_FX_backtest=True')