Example #1
0
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)
Example #2
0
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
Example #3
0
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
Example #4
0
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
Example #5
0
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
Example #6
0
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
Example #7
0
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
Example #8
0
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
Example #9
0
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()))