import argparse import datetime import logging import os import pandas as pd from pandas.tseries.offsets import BDay from analytics import Index, Swaption from db import dbengine from sqlalchemy import exc logging.basicConfig(filename=os.path.join(os.getenv("LOG_DIR"), 'swaption_marks.log'), level=logging.INFO, format='%(asctime)s %(message)s') def get_trades(date, engine): return pd.read_sql_query( "SELECT dealid, buysell, swaption_type, notional, strike, " \ "expiration_date, index, series FROM swaptions " \ "JOIN index_version ON (swaptions.security_id = index_version.redindexcode) " \ "WHERE termination_date is NULL AND expiration_date > %s AND trade_date <= %s", engine, 'dealid', params=(date, date), parse_dates=['expiration_date']) def get_swaptionvol(index, series, strike, expiry, date, engine): r = engine.execute( "SELECT ref, vol_payer AS payer, vol_receiver AS receiver, " \ "vol_payer_black AS payer_black, vol_receiver_black AS receiver_black " \ "FROM swaption_calib LEFT JOIN swaption_ref_quotes " \ "USING (quotedate, expiry, index, series) WHERE index = %s " \ "AND series = %s AND strike=%s AND expiry = %s AND quotedate::date=%s " \ "ORDER BY quotedate desc", (index, series, strike, expiry, date)) try: result = r.fetchone() if result is None: logging.error("No data for {}{} {}K {} expiry on date {}". format(index, series, strike, expiry, date)) return result except exc.DataError as e: logging.error(e) except e: logging.error(e) def mark_trades(date, engine): df = get_trades(date, engine) result = [] for trade in df.itertuples(): try: r = engine.execute("SELECT closespread, closeprice FROM index_quotes " \ "WHERE index=%s AND series=%s AND tenor='5yr' AND date=%s", (trade.index, trade.series, date)) closespread, closeprice = r.fetchone() except exc.DataError as e: logging.eror(e) except TypeError: logging.error("no quote for {}{} {} on date {}".format( trade.index, trade.series, '5yr', date)) underlying = Index.from_name(trade.index, trade.series, '5yr', date, trade.notional) quote = get_swaptionvol(trade.index, trade.series, trade.strike, trade.expiration_date.date(), date, serenitas_engine) if quote is None: continue underlying.ref = quote.ref swaption = Swaption(underlying, trade.expiration_date.date(), trade.strike, trade.swaption_type.lower()) swaption.sigma = getattr(quote, swaption.option_type) if swaption.sigma is None: swaption.sigma = quote.receiver if option_type == "payer" else quote.payer direction = 1. if trade.buysell else -1. market_value = swaption.pv * trade.notional * direction if trade.index in ["HY", "XO"]: market_value += (quote.ref - closeprice) / 100 * swaption.delta * trade.notional * direction else: market_value += swaption.DV01 * (closespread - quote.ref) * trade.notional * direction #compute the greeks at index mark swaption.index.spread = closespread swaption._update() try: to_insert = (trade.Index, date, market_value, swaption.delta, swaption.gamma, swaption.vega) engine.execute("INSERT INTO swaption_marks VALUES(%s, %s, %s, %s, %s, %s)", to_insert) except exc.DataError as e: logging.error(e) finally: logging.info("succesfully marked trade id: %s", trade.Index) return result if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('workdate', nargs='?', type = lambda s: pd.datetime.strptime(s, "%Y-%m-%d").date()), dawn_engine = dbengine('dawndb') serenitas_engine = dbengine('serenitasdb') args = parser.parse_args() if args.workdate is None: workdate = (pd.Timestamp.today()-BDay()).date() else: workdate = args.workdate r = mark_trades(workdate, dawn_engine)