def has_diff(qa_data, bas_data, tolerance): if type(qa_data) == str or type(bas_data) == str: return qa_data != bas_data else: qa_num = 0 if qa_data is None or utils.is_nan(qa_data) else np.float( qa_data) bas_num = 0 if bas_data is None or utils.is_nan( bas_data) else np.float(bas_data) diff = abs(bas_data - qa_num) return diff > tolerance and (abs(diff / bas_num) > tolerance if bas_num != 0 else True)
def get_message(row, multi_asset_position_ids): message = row.get('message', '') pid = row.get('positionId', '') requests = ['price', 'deltas', 'gammas', 'vegas', 'theta'] if pid in multi_asset_position_ids \ else ['price', 'delta', 'gamma', 'vega', 'theta', 'rhoR'] if utils.is_nan(message): for req in requests: if utils.is_nan(np.float64(row[req])): return '定价返回空' return '' else: return message
def process_single_asset_pos(positions, cash_flows, risks, domain, headers, params): all_data = positions.merge(cash_flows, on='positionId', how='left') \ .merge(risks.drop(['quantity'], axis=1), on='positionId', how='left') report = all_data[['positionId', 'bookName', 'counterPartyName', 'tradeId', 'asset.underlyerInstrumentId', 'productType', 'initialNumber', 'unwindNumber', 'tradeDate', 'asset.expirationDate', 'asset.underlyerMultiplier', 'price', 'delta', 'gamma', 'vega', 'theta', 'message', 'q', 'r', 'quantity', 'actualPremium', 'open', 'underlyerPrice', 'rhoR', 'unwind', 'settle', 'vol']] report.rename(columns={'counterPartyName': 'partyName', 'asset.underlyerInstrumentId': 'underlyerInstrumentId', 'asset.expirationDate': 'expirationDate', 'asset.underlyerMultiplier': 'underlyerMultiplier'} , inplace=True) # for cash flows: underlyerPrice = 1 cf_idx = report[report['productType'] == _PRODUCT_TYPE_CASH_FLOW].index if len(cf_idx) > 0: report.loc[cf_idx, 'underlyerPrice'] = 1 report['marketValue'] = report['price'] report['number'] = np.float64(report['quantity']) / np.float64(report['underlyerMultiplier']) report['premium'] = report.apply( lambda row: np.float64(row['actualPremium']) if is_nan(row['open']) else np.float64(row['open']), axis=1) report['unwindAmount'] = report.apply( lambda row: 0 if is_nan(row['open']) else np.float64(row['unwind']) + np.float64(row['settle']), axis=1) report['pnl'] = np.float64(report['marketValue']) + report['premium'] + report['unwindAmount'] calc_delta_and_gamma(report) report['vega'] = np.float64(report['vega']) / 100 report['theta'] = np.float64(report['theta']) / 365 report['rho'] = np.float64(report['rhoR']) / 100 report['deltaDecay'] = np.nan report['deltaWithDecay'] = np.nan report.drop(['quantity', 'actualPremium', 'open', 'underlyerPrice', 'rhoR', 'unwind', 'settle'], axis=1, inplace=True) params['tradeIds'] = list(report.tradeId.unique()) decay_data = call_request(domain, 'pricing-service', 'prcPrice', params, headers) if 'result' in decay_data: diagnostics_pd = json_normalize(decay_data['diagnostics']) diagnostics_pd = pd.DataFrame(decay_data['diagnostics']) if not diagnostics_pd.empty: diagnostics_pids = list(diagnostics_pd.key.unique()) diagnostics_pd.set_index('key', inplace=True) diagnostics_pd.drop_duplicates(inplace=True) report['message'] = report.apply(lambda row: get_error_msg(row, diagnostics_pd, diagnostics_pids), axis=1) risk_pd = json_normalize(decay_data['result']) risk_pd = pd.DataFrame(decay_data['result']) if not risk_pd.empty: risk_pids = list(risk_pd.positionId.unique()) risk_pd = risk_pd.set_index('positionId') report['deltaWithDecay'] = report.apply(lambda row: calc_delta_with_decay(row, risk_pd, risk_pids), axis=1) report['deltaDecay'] = report['deltaWithDecay'] - report['delta'] report['listedOption'] = False return report
def calc_delta_with_decays(row, risk_pd, risk_pids): pid = row['positionId'] result = row['deltaWithDecays'] if pid in risk_pids: result = [get_val(risk_pd.loc[pid]['deltas'], 0) / get_val(row['underlyerMultipliers'], 0), get_val(risk_pd.loc[pid]['deltas'], 1) / get_val(row['underlyerMultipliers'], 1)] return [np.nan, np.nan] if is_nan(result) else result
def actual_premium(data): """Return actual premium in origin currency.""" if data['productType'] == _PRODUCT_TYPE_CASH_FLOW: return 0 premium = np.float64(data['asset.premium']) premium_type = data['asset.premiumType'] notional = np.float64(data['asset.actualNotional']) direction = data['asset.direction'] if utils.is_nan(premium): return 0 sign = -1 if direction == _DIRECTION_BUYER else 1 return sign * premium * notional if premium_type == _UNIT_TYPE_PERCENT else sign * premium
def actual_notional(data): """Return actual notional in origin currency.""" if data['productType'] == _PRODUCT_TYPE_CASH_FLOW: return data['asset.paymentAmount'] notional = np.float64(data['asset.notionalAmount']) notional_type = data['asset.notionalAmountType'] annualized = data['asset.annualized'] term = np.float64(data['asset.term']) days_in_year = np.float64(data['asset.daysInYear']) init_spot = np.float64(data['asset.initialSpot']) multiplier = np.float64(data['asset.underlyerMultiplier']) if utils.is_nan(notional): return 0 notional_in_currency = notional if notional_type != _UNIT_TYPE_LOT else notional * init_spot * multiplier return notional_in_currency * term / days_in_year if annualized else notional_in_currency
def process_multi_asset_pos(positions, cash_flows, risks, domain, headers, params): all_data = positions.merge(cash_flows, on='positionId', how='left').merge(risks, on='positionId', how='left') rpt = all_data[['positionId', 'bookName', 'counterPartyName', 'tradeId', 'asset.underlyerInstrumentId1', 'vegas', 'asset.underlyerInstrumentId2', 'productType', 'initialNumber1', 'initialNumber2', 'gammas', 'r', 'unwindNumber1', 'unwindNumber2', 'tradeDate', 'asset.expirationDate', 'message', 'deltas', 'qs', 'asset.underlyerMultiplier1', 'asset.underlyerMultiplier2', 'price', 'theta', 'settle', 'vols', 'quantity1', 'quantity2', 'actualPremium', 'open', 'underlyerPrices', 'rhoR', 'unwind']] rpt.rename(columns={'counterPartyName': 'partyName', 'asset.expirationDate': 'expirationDate'}, inplace=True) rpt['marketValue'] = rpt['price'] rpt['underlyerInstrumentIds'] = rpt.apply( lambda r: [r['asset.underlyerInstrumentId1'], r['asset.underlyerInstrumentId2']], axis=1) # TODO: 这种写法可能会有性能问题,但考虑到只是针对多资产交易,数量少,暂时这样做。若以后交易量大,后台应提供相应批量查询接口以避免频繁调用接口 rpt['correlation'] = rpt.apply(lambda r: get_correlation(r['underlyerInstrumentIds'], domain, headers), axis=1) rpt['underlyerMultipliers'] = rpt.apply( lambda r: [r['asset.underlyerMultiplier1'], r['asset.underlyerMultiplier2']], axis=1) rpt['initialNumbers'] = rpt.apply(lambda r: [r['initialNumber1'], r['initialNumber2']], axis=1) rpt['unwindNumbers'] = rpt.apply(lambda r: [r['unwindNumber1'], r['unwindNumber2']], axis=1) rpt['numbers'] = rpt.apply(lambda row: [np.float64(row['quantity1']) / row['underlyerMultipliers'][0], np.float64(row['quantity2']) / row['underlyerMultipliers'][1]], axis=1) rpt['premium'] = rpt.apply( lambda row: np.float64(row['actualPremium']) if is_nan(row['open']) else np.float64(row['open']), axis=1) rpt['unwindAmount'] = rpt.apply( lambda row: 0 if is_nan(row['open']) else np.float64(row['unwind']) + np.float64(row['settle']), axis=1) rpt['pnl'] = np.float64(rpt['marketValue']) + rpt['premium'] + rpt['unwindAmount'] rpt['deltas'] = rpt.apply(lambda r: [get_val(r['deltas'], 0) / get_val(r['underlyerMultipliers'], 0), get_val(r['deltas'], 1) / get_val(r['underlyerMultipliers'], 1)], axis=1) rpt['deltaCashes'] = rpt.apply(lambda r: [np.float64(r['deltas'][0]) * get_val(r['underlyerPrices'], 0), np.float64(r['deltas'][1]) * get_val(r['underlyerPrices'], 1)], axis=1) rpt['gammas'] = rpt.apply( lambda r: [get_val(r['gammas'], 0, 0) * get_val(r['underlyerPrices'], 0) / r['underlyerMultipliers'][0] / 100, get_val(r['gammas'], 1, 1) * get_val(r['underlyerPrices'], 1) / r['underlyerMultipliers'][1] / 100], axis=1) rpt['gammaCashes'] = rpt.apply(lambda r: [np.float64(r['gammas'][0]) * get_val(r['underlyerPrices'], 0), np.float64(r['gammas'][1]) * get_val(r['underlyerPrices'], 1)], axis=1) rpt['vegas'] = rpt.apply(lambda r: [get_val(r['vegas'], 0) / 100, get_val(r['vegas'], 1) / 100], axis=1) rpt['theta'] = np.float64(rpt['theta']) / 365 rpt['rho'] = np.float64(rpt['rhoR']) / 100 rpt['deltaDecays'] = np.nan rpt['deltaWithDecays'] = np.nan rpt.drop(['asset.underlyerInstrumentId1', 'asset.underlyerInstrumentId2', 'asset.underlyerMultiplier1', 'quantity1', 'asset.underlyerMultiplier2', 'initialNumber1', 'initialNumber2', 'rhoR', 'quantity2', 'actualPremium', 'open', 'settle', 'unwindNumber1', 'unwindNumber2', 'underlyerPrices', 'unwind'], axis=1, inplace=True) params['tradeIds'] = list(rpt.tradeId.unique()) decay_data = call_request(domain, 'pricing-service', 'prcPrice', params, headers) if 'result' in decay_data: diagnostics_pd = pd.DataFrame(decay_data['diagnostics']) if not diagnostics_pd.empty: diagnostics_pids = list(diagnostics_pd.key.unique()) diagnostics_pd.set_index('key', inplace=True) diagnostics_pd.drop_duplicates(inplace=True) rpt['message'] = rpt.apply(lambda row: get_error_msg(row, diagnostics_pd, diagnostics_pids), axis=1) risk_pd = pd.DataFrame(decay_data['result']) if not risk_pd.empty: risk_pids = list(risk_pd.positionId.unique()) risk_pd = risk_pd.set_index('positionId') rpt['deltaWithDecays'] = rpt.apply(lambda row: calc_delta_with_decays(row, risk_pd, risk_pids), axis=1) rpt['deltaDecays'] = rpt.apply(lambda r: [get_val(r['deltaWithDecays'], 0) - get_val(r['deltas'], 0), get_val(r['deltaWithDecays'], 1) - get_val(r['deltas'], 1)], axis=1) rpt['listedOption'] = False return rpt
def intraday_risk_by_underlyer_report(positions, underlyer_positions, domain, headers, pricing_environment): """Return intraday risk collected by book and underlyer. positions: intraday position report underlyer_positions: basic underlyer position report""" # find books and underlyers books = set([p['bookName'] for p in positions]) books.update(underlyer_positions.keys()) book_underlyer = {b: set() for b in books} for p in positions: book_underlyer[p['bookName']].add(p['underlyerInstrumentId']) for b, u in underlyer_positions.items(): book_underlyer[b].update( [l['underlyerInstrumentId'] for l in u.values()]) # get quotes underlyers = set() for b in book_underlyer.values(): for u in b: underlyers.add(u) underlyers = list(underlyers) quotes = get_underlyer_quotes(underlyers, datetime.now(), domain, headers) yst_quotes = get_underlyer_quotes(underlyers, datetime.now() - timedelta(days=1), domain, headers) # empty report risks = {b: {} for b in books} for b in book_underlyer: for u in book_underlyer[b]: spot = quotes[u]['last'] if spot is None or spot == 0: continue spot_change_ratio = ( spot - np.float64(yst_quotes.get(u).get('close'))) / spot risks[b][u] = { 'bookName': b, 'underlyerInstrumentId': u, 'underlyerPrice': spot, 'underlyerNetPosition': 0, 'delta': 0, 'deltaCash': 0, 'netDelta': 0, 'deltaDecay': 0, 'deltaWithDecay': 0, 'gamma': 0, 'gammaCash': 0, 'vega': 0, 'theta': 0, 'rho': 0 } if not utils.is_nan(spot_change_ratio): risks[b][u]['underlyerPriceChangePercent'] = spot_change_ratio # underlyer positions for b in underlyer_positions.values(): for u in b.values(): if risks[u['bookId']].get(u['instrumentId']) is None: continue r = risks[u['bookId']][u['instrumentId']] spot = u['underlyerPrice'] multiplier = u['underlyerInstrumentMultiplier'] r['underlyerMultiplier'] = multiplier if u['instrumentId'] == u['underlyerInstrumentId']: r['underlyerNetPosition'] += u['netPosition'] else: r['delta'] += u['delta'] / multiplier r['gamma'] += u['gamma'] * spot / 100 / multiplier r['gammaCash'] += u['gamma'] * spot * spot / 100 / multiplier r['vega'] += u['vega'] / 100 r['theta'] += u['theta'] / 365 r['rho'] += u['rhoR'] / 100 # option risks def add_risk(positions): for p in positions: if has_pricing_error(p): continue r = risks[p['bookName']][p['underlyerInstrumentId']] r['delta'] += p['delta'] r['deltaDecay'] += p['deltaDecay'] r['deltaWithDecay'] += p['deltaWithDecay'] r['gamma'] += p['gamma'] r['gammaCash'] += p['gammaCash'] r['vega'] += p['vega'] r['theta'] += p['theta'] r['rho'] += p['rho'] if r.get('underlyerMultiplier', None) is None: r['underlyerMultiplier'] = p['underlyerMultiplier'] add_risk(positions) # net delta for b in risks: for u in risks[b]: r = risks[b][u] if r.get('underlyerMultiplier', None) is None: continue r['netDelta'] = r['delta'] + r['underlyerNetPosition'] r['deltaCash'] = r['netDelta'] * r['underlyerPrice'] * r[ 'underlyerMultiplier'] r.pop('underlyerMultiplier') # flatten report = [] for b in risks: report.extend(list(risks[b].values())) timestamp = str(datetime.now()) for re in report: re['pricingEnvironment'] = pricing_environment re['createdAt'] = timestamp return report
def intraday_expiring_position_report(expirings, risks, cash_flows): """Return report on positions expire today. expirings: expiring positions from basic position report risks: basic risk report cash_flows: basic cash flow report """ if expirings.empty: return [] # cash flow cash_flows_data = cash_flows[['positionId', 'open', 'unwind', 'settle']].set_index('positionId') expirings_data = expirings[[ 'positionId', 'bookName', 'counterPartyName', 'tradeId', 'asset.underlyerInstrumentId', 'productType', 'initialNumber', 'unwindNumber', 'tradeDate', 'asset.expirationDate', 'asset.underlyerMultiplier', 'quantity' ]].set_index('positionId') risks_data = risks[[ 'price', 'delta', 'underlyerPrice', 'gamma', 'vega', 'theta', 'rhoR', 'message', 'pricing_environment' ]] report_data = expirings_data.join(risks_data).join(cash_flows_data) report_data.rename(columns={ 'counterPartyName': 'partyName', 'asset.underlyerInstrumentId': 'underlyerInstrumentId', 'asset.underlyerMultiplier': 'underlyerMultiplier', 'price': 'marketValue', 'asset.expirationDate': 'expirationDate', 'pricing_environment': 'pricingEnvironment', 'rhoR': 'rho' }, inplace=True) report_data['premium'] = report_data.apply( lambda row: np.float64(row['actualPremium']) if utils.is_nan(row['open']) else np.float64(row['open']), axis=1) report_data['unwindAmount'] = report_data.apply( lambda row: 0 if utils.is_nan(row['open']) else np.float64(row[ 'unwind']) + np.float64(row['settle']), axis=1) report_data['number'] = np.float64(report_data['quantity']) / np.float64( report_data['underlyerMultiplier']) report_data['pnl'] = np.float64( report_data['marketValue'] ) + report_data['premium'] + report_data['unwindAmount'] report_data['delta'] = np.float64(report_data['delta']) / np.float64( report_data['underlyerMultiplier']) report_data['deltaCash'] = np.float64(report_data['delta']) * np.float64( report_data['underlyerPrice']) report_data['gamma'] = np.float64(report_data['gamma']) * np.float64( report_data['underlyerPrice']) / np.float64( report_data['underlyerMultiplier']) / 100 report_data['gammaCash'] = report_data['gamma'] * np.float64( report_data['underlyerPrice']) * np.float64( report_data['underlyerMultiplier']) report_data['vega'] = np.float64(report_data['vega']) / 100 report_data['theta'] = np.float64(report_data['theta']) / 365 report_data['rho'] = np.float64(report_data['rho']) / 100 report_data['deltaDecay'] = np.float64(report_data['delta']) * -1 report_data['deltaWithDecay'] = 0 report_data['createdAt'] = str(datetime.now()) report_data.drop( ['open', 'unwind', 'settle', 'quantity', 'underlyerPrice'], inplace=True, axis=1) report_data.fillna('', inplace=True) return utils.remove_nan_and_inf( list(report_data.reset_index().to_dict(orient='index').values()))