import argparse import datetime import logging import os import pandas as pd from pandas.tseries.offsets import BDay from analytics import Index, Swaption, Portfolio, BlackSwaption 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_swaption_portfolio(date, engine): tradeids = engine.execute("SELECT id FROM swaptions WHERE termination_date is NULL " "AND expiration_date > %s AND trade_date <= %s", (date, date)) portf = Portfolio([BlackSwaption.from_tradeid(r[0]) for r in tradeids]) portf.value_date = date portf.mark(interp_method='bivariate_linear') return portf 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_quotes USING (quote_id) " \ "LEFT JOIN swaption_ref_quotes USING (ref_id) "\ "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 swaption.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)