def __init__(self,
              date=None,
              end_time='21:00:00',
              end_time_loop='20:00:00',
              polygon_method=None,
              symbol_status=None,
              collection_name=None,
              insert_into_collection=None):
     self.helperObj = Helper()
     self.date = date
     self.extract_data_till_time = self.helperObj.stringTimeToDatetime(
         date=date, time=end_time_loop)
     self.end_ts = self.helperObj.convertHumanTimeToUnixTimeStamp(
         date=date, time=end_time)
     self.polygon_method = polygon_method
     self.insert_into_collection = insert_into_collection
     self.collection_name = collection_name
     self.symbol_status = symbol_status
Ejemplo n.º 2
0
def fetchOHLCHistoricalData(etfname=None, StartDate=None):
    ob = HistoricOHLC()
    data = ob.getopenlowhistoric(etfname=etfname, startdate=StartDate)
    del data['n']
    data.rename(columns={
        'v': 'volume',
        'o': 'open',
        'c': 'close',
        'h': 'high',
        'l': 'low',
        't': 'date'
    },
                inplace=True)
    # Helper Class from PolygonTickData.Helper for converting uni timestamp to human timestamp
    helperObjTimeConversion = Helper()
    data['date'] = data['date'].apply(
        lambda x: helperObjTimeConversion.getHumanTime(ts=x, divideby=1000))
    return data
 def __init__(self, symbols=None, date=None):
     self.date = date
     self.endTs = Helper().convertHumanTimeToUnixTimeStamp(date=self.date,
                                                           time='17:00:00')
     self.symbols = symbols
     self.mtqd = MongoTradesQuotesData()
Ejemplo n.º 4
0
from datetime import datetime, timedelta, date
from MongoDB.MongoDBConnections import MongoDBConnectors
from CalculateETFArbitrage.Helpers.LoadEtfHoldings import LoadHoldingsdata
from CommonServices.Holidays import LastWorkingDay
from PolygonTickData.Helper import Helper
from dataclasses import dataclass

sys_private_ip = socket.gethostbyname(socket.gethostname())
if sys_private_ip == '172.31.76.32':
    connection = MongoDBConnectors(
    ).get_pymongo_readWrite_production_production()
else:
    connection = MongoDBConnectors().get_pymongo_devlocal_devlocal()
per_sec_trades_db = connection.ETF_db.PerSecLiveTrades
per_sec_quotes_db = connection.ETF_db.PerSecLiveQuotes
helper_object = Helper()


class TradeStruct(
):  # For Trade Objects, containing current minute and last minute price for Tickers
    __slots__ = ['symbol', 'priceT', 'priceT_1', 'price_pct_chg']

    def calc_pct_chg(self, priceT, priceT_1):
        if priceT_1 == 0:
            return 0
        return ((priceT - priceT_1) / priceT_1) * 100

    def __init__(self, symbol, priceT, priceT_1=None):
        self.symbol = symbol
        self.priceT = priceT
        if not priceT_1:
def fecthArbitrageANDLivePrices(etfname=None,
                                FuncETFPrices=None,
                                FuncArbitrageData=None,
                                callAllDayArbitrage=None):
    try:
        # Full day historical Prie for ETF
        PriceDF = FuncETFPrices(etfname)
        #PriceDF['Price'] = (PriceDF['high']+PriceDF['low'])/2
        # Full day historical Arbitrage for ETF
        ArbitrageDFSemi = FuncArbitrageData(etfname=etfname)

        # noh = list(MongoDBConnectors().get_pymongo_readonly_devlocal_production().ETF_db.ETFHoldings.find({'ETFTicker':etfname},{'_id':0, 'NumberOfHolding':1}).sort([('FundHoldingsDate',-1)]).limit(1))[0]['NumberOfHolding']
        # x = noh if noh<10 else 10
        # etmoverslist = ['ETFMover%{}'.format(i+1) for i in range(x)]
        # changes = ['Change%{}'.format(i+1) for i in range(x)]
        # etmoverslist.extend(changes)

        ArbitrageDf = ArbitrageDFSemi.merge(PriceDF,
                                            left_on='Timestamp',
                                            right_on='date',
                                            how='left')
        ArbitrageDf = ArbitrageDf[[
            'symbol', 'Timestamp', 'Arbitrage in $', 'ETF Trading Spread in $',
            'TickVolume', 'Net Asset Value Change%', 'ETF Change Price %',
            'ETF Price'
        ] + etmoverslist]
        ArbitrageDf = ArbitrageDf.round(5)

        helperObj = Helper()
        PriceDF['date'] = PriceDF['date'].apply(
            lambda x: helperObj.getHumanTime(ts=x, divideby=1000) - timedelta(
                hours=daylightSavingAdjutment))
        ArbitrageDf['Timestamp'] = ArbitrageDf['Timestamp'].apply(
            lambda x: str((helperObj.getHumanTime(ts=x, divideby=1000) -
                           timedelta(hours=daylightSavingAdjutment)).time()))
        """Add one minute to each to make end timestamp from start timestamp"""
        PriceDF['date'] = PriceDF['date'] + timedelta(minutes=1)
        ArbitrageDf['Timestamp'] = ArbitrageDf['Timestamp'].apply(
            lambda x: str((datetime.strptime(x, '%H:%M:%S') + timedelta(
                minutes=1)).time()))

        ArbitrageDf.rename(columns={'Timestamp': 'Time'}, inplace=True)

        res = {}
        res['Prices'] = PriceDF[::-1]

        # All day analysis
        if callAllDayArbitrage:
            PriceDFcopy = PriceDF.copy()
            PriceDFcopy['date'] = PriceDFcopy['date'].apply(
                lambda x: x.strftime('%H:%M:%S'))
            PriceDFcopy.rename(columns={
                'open': 'Open',
                'close': 'Close',
                'high': 'High',
                'low': 'Low'
            },
                               inplace=True)
            cols_to_use_right = PriceDFcopy.columns.difference(
                ArbitrageDf.columns)
            ArbitrageDf = ArbitrageDf.merge(PriceDFcopy[cols_to_use_right],
                                            left_on='Time',
                                            right_on='date',
                                            how='left')

            arbitrageBuySellSignals, pnlstatementforday, scatterPlotData = calculateArbitrageResults(
                df=ArbitrageDf,
                etfname=etfname,
                magnitudeOfArbitrageToFilterOn=0,
                BuildMomentumSignals=False,
                BuildPatternSignals=True,
                includeMovers=True,
                getScatterPlot=False)

            cols_to_use = ArbitrageDf.columns.difference(
                arbitrageBuySellSignals.columns)
            arbitrageBuySellSignals['Time'] = arbitrageBuySellSignals.index
            arbitrageBuySellSignals = arbitrageBuySellSignals.merge(
                ArbitrageDf[cols_to_use],
                left_on='Time',
                right_on='Time',
                how='left')

            del arbitrageBuySellSignals['ETF Change Price %']
            arbitrageBuySellSignals.rename(columns={'T': 'ETF Change Price %'},
                                           inplace=True)

            arbitrageBuySellSignals['ETFName'] = etfname
            ##arbitrageBuySellSignals['ETF Change Price %']=np.round(arbitrageBuySellSignals['ETF Change Price %'],2)
            #arbitrageBuySellSignals['Price'] = np.round(arbitrageBuySellSignals['Price'],2)

            #arbitrageBuySellSignals.Price=arbitrageBuySellSignals.Price.round(2)
            arbitrageBuySellSignals[
                'ETF Change Price %'] = arbitrageBuySellSignals[
                    'ETF Change Price %'].round(3)

            arbitrageBuySellSignals = arbitrageBuySellSignals

            res['Arbitrage'] = arbitrageBuySellSignals
            res['pnlstatementforday'] = pnlstatementforday
        else:
            res['Arbitrage'] = ArbitrageDf

        return res

    except Exception as e:
        print("Issue in Flask app while fetching ETF Description Data")
        print(traceback.format_exc())
        exc_type, exc_value, exc_tb = sys.exc_info()
        return MultipleExceptionHandler().handle_exception(
            exception_type=exc_type, e=e, custom_logger=custom_server_logger)
 def __init__(self):
     self.helper_obj = Helper()
     self.trade_prices_df_minutes = pd.DataFrame()
class ArbitrageCalculation():
    def __init__(self):
        self.helper_obj = Helper()
        self.trade_prices_df_minutes = pd.DataFrame()

    def fetch_all_data(self, etf_name, date):
        """Load the ETF Holding"""
        etf_data = LoadHoldingsdata().LoadHoldingsAndClean(
            etfname=etf_name, fundholdingsdate=date)
        '''Load all the data - Holdings data for Etf, trade data, quotes data, open-close price'''
        all_data = DataApi(etfname=etf_name, date=date, etfData=etf_data)
        all_data.run_all_data_ops()
        return etf_data, all_data

    def trades_data_formatting_cleaning(self, all_data):
        all_data.tradesDataDf['Time'] = all_data.tradesDataDf['Time'].apply(
            lambda x: self.helper_obj.getHumanTime(ts=x, divideby=1000))
        self.trade_prices_df_minutes = \
            all_data.tradesDataDf.groupby([all_data.tradesDataDf['Time'], all_data.tradesDataDf['Symbol']])[
                'Trade Price']
        self.trade_prices_df_minutes = self.trade_prices_df_minutes.first(
        ).unstack(level=1)

        price_for_nav_filling = all_data.openPriceData.set_index(
            'Symbol').T.to_dict('records')[0]

        market_start_time = datetime.datetime.strptime('13:29:00',
                                                       "%H:%M:%S").time()
        market_end_time = datetime.datetime.strptime('20:00:00',
                                                     "%H:%M:%S").time()

        mask = (self.trade_prices_df_minutes.index.time >=
                market_start_time) & (self.trade_prices_df_minutes.index.time
                                      <= market_end_time)
        self.trade_prices_df_minutes = self.trade_prices_df_minutes[mask]
        self.trade_prices_df_minutes = self.trade_prices_df_minutes.ffill(
            axis=0)
        self.trade_prices_df_minutes = self.trade_prices_df_minutes.fillna(
            price_for_nav_filling)
        return self.trade_prices_df_minutes

    def calculate_etf_price_change(self, etf_name):
        etf_price = self.trade_prices_df_minutes[etf_name]
        self.trade_prices_df_minutes = self.trade_prices_df_minutes.pct_change(
        ).dropna() * 100
        etf_price_change = self.trade_prices_df_minutes[etf_name]
        return etf_price, etf_price_change

    def calculate_etf_trading_spread(self, all_data):
        """Trading Spread Calculation"""
        all_data.quotesDataDf['Time'] = all_data.quotesDataDf['Time'].apply(
            lambda x: self.helper_obj.getHumanTime(ts=x, divideby=1000000000))
        all_data.quotesDataDf['Time'] = all_data.quotesDataDf['Time'].map(
            lambda x: x.replace(second=0))
        all_data.quotesDataDf = all_data.quotesDataDf[
            all_data.quotesDataDf['Bid Size'] != 0]
        all_data.quotesDataDf = all_data.quotesDataDf[
            all_data.quotesDataDf['Ask Size'] != 0]
        all_data.quotesDataDf['Total Bid Ask Size'] = all_data.quotesDataDf[
            'Ask Size'] + all_data.quotesDataDf['Bid Size']
        all_data.quotesDataDf['Spread'] = all_data.quotesDataDf[
            'Ask Price'] - all_data.quotesDataDf['Bid Price']
        all_data.quotesDataDf['MidPrice'] = (
            all_data.quotesDataDf['Ask Price'] +
            all_data.quotesDataDf['Bid Price']) / 2
        quotes_spreads_minutes = all_data.quotesDataDf.groupby(
            'Time')['Spread'].mean()
        return quotes_spreads_minutes

    def calculateArbitrage(self, etf_name, date):
        """CALCULATE ETF ARBITRAGE FOR THE DATE"""
        etf_data, all_data = self.fetch_all_data(etf_name, date)
        '''Check if any holdings is trading in Non-US markets'''
        if all_data.openPriceData is None:
            return None
        '''Trade Prices formatting between 13.29 and 20.00'''
        self.trade_prices_df_minutes = self.trades_data_formatting_cleaning(
            all_data)
        '''Calculate Change in ETF Trade Price'''
        etf_price, etf_price_change = self.calculate_etf_price_change(etf_name)
        del self.trade_prices_df_minutes[etf_name]
        '''Trading Spread Calculation'''
        quotes_spreads_minutes = self.calculate_etf_trading_spread(all_data)
        '''Arbitrage Calculation'''
        net_asset_value_return = self.trade_prices_df_minutes.assign(
            **etf_data.getETFWeights()).mul(
                self.trade_prices_df_minutes).sum(axis=1)
        ds = pd.concat([
            etf_price, etf_price_change, net_asset_value_return,
            quotes_spreads_minutes
        ],
                       axis=1).dropna()
        ds.columns = [
            'ETF Price', 'ETF Change Price %', 'Net Asset Value Change%',
            'ETF Trading Spread in $'
        ]
        ds['Arbitrage in $'] = (
            ds['ETF Change Price %'] -
            ds['Net Asset Value Change%']) * ds['ETF Price'] / 100
        ds['Flag'] = 0
        ds.loc[(abs(ds['Arbitrage in $']) > ds['ETF Trading Spread in $'])
               & ds['ETF Trading Spread in $'] != 0, 'Flag'] = 111
        ds['Flag'] = ds['Flag'] * np.sign(ds['Arbitrage in $'])
        ''' Movers and Changes '''
        holdings_change = self.helper_obj.EtfMover(
            df=self.trade_prices_df_minutes, columnName='Change%')
        etf_mover_holdings = self.helper_obj.EtfMover(
            df=self.trade_prices_df_minutes.assign(
                **etf_data.getETFWeights()).mul(
                    self.trade_prices_df_minutes).dropna(axis=1),
            columnName='ETFMover%')
        '''Final Calculated Result DataFrame'''
        ds = pd.concat([ds, etf_mover_holdings, holdings_change], axis=1)
        print(ds)
        return ds
class FetchPolygonData(object):
    """Fetch and Store Methods for Trades/Quotes Data from Polygon.io"""
    def __init__(self,
                 date=None,
                 end_time='21:00:00',
                 end_time_loop='20:00:00',
                 polygon_method=None,
                 symbol_status=None,
                 collection_name=None,
                 insert_into_collection=None):
        self.helperObj = Helper()
        self.date = date
        self.extract_data_till_time = self.helperObj.stringTimeToDatetime(
            date=date, time=end_time_loop)
        self.end_ts = self.helperObj.convertHumanTimeToUnixTimeStamp(
            date=date, time=end_time)
        self.polygon_method = polygon_method
        self.insert_into_collection = insert_into_collection
        self.collection_name = collection_name
        self.symbol_status = symbol_status

    def data_operation_runner(self, url):
        """Main for running Quotes data fetching operations"""
        pagination = url
        retry_counter = 2
        while pagination:
            response = self.response_from_api(pagination)
            while retry_counter > 0 and response['success'] == False:
                retry_counter -= 1
                print("Response failure from polygon")
                logger.error("Response failure from polygon")
                response = self.response_from_api(pagination)
            pagination_ = self.extract_data_from_response_and_store(response)
            pagination = pagination_ if pagination_ != pagination else None

    def response_from_api(self, url):
        """Get Quotes data from API URL"""
        session = requests.Session()
        retry = Retry(connect=3, backoff_factor=0.5)
        adapter = HTTPAdapter(max_retries=retry)
        session.mount('http://', adapter)
        session.mount('https://', adapter)
        response = session.get(url)
        delay = response.headers.get("DELAY")
        date = response.headers.get("DATE")
        print("{}:{} with delay {}".format(date, response.url, delay))
        json_data = json.loads(response.text)
        return json_data

    def extract_data_from_response_and_store(self, response):
        """Extract data from response, check for pagination, store the data"""
        pagination_request = None
        symbol = response['ticker']
        print("Symbol being processed " + symbol)
        response_data = [
            dict(item, **{'Symbol': symbol}) for item in response['results']
            if response['results']
        ]
        last_unix_time_stamp = self.helperObj.getLastTimeStamp(response)
        print("Fetched till time for =" +
              str(self.helperObj.getHumanTime(last_unix_time_stamp)))
        logger.debug("Fetched till time for = {}".format(
            str(self.helperObj.getHumanTime(last_unix_time_stamp))))

        if self.helperObj.checkTimeStampForPagination(
                last_unix_time_stamp, self.extract_data_till_time):
            pagination_request = self.polygon_method(
                date=self.date,
                symbol=symbol,
                startTS=str(last_unix_time_stamp),
                endTS=self.end_ts,
                limitresult=str(50000))
            self.symbol_status[symbol]['batchSize'] += 1

        _ = self.insert_into_collection(
            symbol=symbol,
            datetosave=self.date,
            savedata=response_data,
            CollectionName=self.collection_name,
            batchSize=self.symbol_status[symbol]['batchSize'])
        print("Pagination Request = {}".format(pagination_request))
        logger.debug("Pagination Request = {}".format(pagination_request))
        if pagination_request:
            return pagination_request
        else:
            print("No Pagination Required for = " + symbol)
            logger.debug("No Pagination Required for = {}".format(symbol))
            return None

    """Trades Get Operations"""

    async def get_trade_data_and_save(self, url, session):
        """Get Trades data from API URL Asynchronously"""
        try:
            async with session.get(url) as response:
                delay = response.headers.get("DELAY")
                date = response.headers.get("DATE")
                print("{}:{} with delay {}".format(date, response.url, delay))
                json_data = json.loads(await response.text())
                symbol = json_data['ticker']
                if 'results' not in json_data:
                    print(f"No results for {symbol}")
                data = [
                    dict(item, **{'Symbol': symbol})
                    for item in json_data['results'] if 'results' in json_data
                ]
                self.insert_into_collection(
                    symbol=symbol,
                    datetosave=self.date,
                    savedata=data,
                    CollectionName=self.collection_name)
                print(f'inserted {symbol} data')
        except KeyError:
            print(
                f"################################ No results for {symbol} ################################"
            )
            logger.warn(
                f"################################ No results for {symbol} ################################"
            )

    async def task_creator_and_gatherer(self, func, iterable):
        """Asynchronous Main for Trades data fetching operations"""
        async with ClientSession() as session:
            tasks = [
                asyncio.ensure_future(func(url, session)) for url in iterable
            ]
            return await asyncio.gather(*tasks)