예제 #1
0
class PolygonData(DataAPI):
    def __init__(self):
        self.polygon_rest_client = RESTClient(config.polygon_api_key)
        if not self.polygon_rest_client:
            raise AssertionError(
                "Failed to authenticate Polygon restful client"
            )

    def get_symbols(self) -> List[Dict]:
        if not self.polygon_rest_client:
            raise AssertionError("Must call w/ authenticated polygon client")

        data = self.polygon_rest_client.stocks_equities_snapshot_all_tickers()
        return data.tickers

    def get_symbol_data(
        self,
        symbol: str,
        start: date,
        end: date = date.today(),
        scale: TimeScale = TimeScale.minute,
    ) -> pd.DataFrame:
        if not self.polygon_rest_client:
            raise AssertionError("Must call w/ authenticated polygon client")

        data = self.polygon_rest_client.stocks_equities_aggregates(
            symbol, 1, scale.name, start, end, unadjusted=False
        )
        if not data or not hasattr(data, "results"):
            raise ValueError(
                f"[ERROR] {symbol} has no data for {start} to {end} w {scale.name}"
            )

        d = {
            pd.Timestamp(result["t"], unit="ms", tz="America/New_York"): [
                result.get("o"),
                result.get("h"),
                result.get("l"),
                result.get("c"),
                result.get("v"),
                result.get("vw"),
                result.get("n"),
            ]
            for result in data.results
        }
        _df = pd.DataFrame.from_dict(
            d,
            orient="index",
            columns=[
                "open",
                "high",
                "low",
                "close",
                "volume",
                "average",
                "count",
            ],
        )
        _df["vwap"] = 0.0
        return _df
예제 #2
0
    def trade(self):
        """
        This function when called begins the cycle of trading. Note that the data the system has access
        to will be the beginDate - lookback, but the first trade will be initiated as if it was done during beginDate
        The Eventual goal for this will be to implement some controls over it in tkinter
        :return:
        """
        client = RESTClient(self.api_key)
        tickers = self.portfolio.tickers
        self.__correct_begin_date()
        for stock in tickers:
            response = client.stocks_equities_aggregates(stock, 1, self.bar_distance,
                                                         self.begin_date - datetime.timedelta(days=1),
                                                         self.end_date + datetime.timedelta(days=1))
            if response.results is None: #Make sure that data is actually gotten
                    raise Exception("Unable to retrieve market data")
            self.asset[stock] = response.results

        while self.date_offset + self.look_back.days < len(self.asset[tickers[0]]) - 1: #TODO Is every stock going to have the exact same amount of days?
            truncated_data = dict()
            for stock in tickers:
                truncated_data[stock] = self.asset[stock][self.date_offset:self.look_back.days + self.date_offset] #Creates the set of data that only includes the current lookback period
            self.trading_func(truncated_data)
            self.date_offset += 1
        self.__calc_pl()
예제 #3
0
    def get_day_quotes(self, ticker, timestamp):
        """Collects all quotes from the day of the market timestamp."""

        polygon_client = PolygonClient(POLYGON_API_KEY)
        quotes = []

        # The timestamp is expected in market time.
        day_str = timestamp.strftime("%Y-%m-%d")
        response = polygon_client.stocks_equities_aggregates(
            ticker, 1, "minute", day_str, day_str)
        if not response or response.status != "OK" or not response.results:
            self.logs.error(
                "Failed to request historical data for %s on %s: %s" %
                (ticker, timestamp, response))
            return None

        for result in response.results:
            try:
                # Parse and convert the current minute's timestamp.
                minute_timestamp = result["t"] / 1000
                minute_market_time = self.utc_to_market_time(
                    datetime.fromtimestamp(minute_timestamp))

                # Use the price at the beginning of the minute.
                price = result["o"]
                if not price or price < 0:
                    self.logs.warn("Invalid price: %s" % price)
                    continue

                quote = {"time": minute_market_time, "price": price}
                quotes.append(quote)
            except (KeyError, TypeError, ValueError) as e:
                self.logs.warn("Failed to parse result: %s" % e)

        return quotes
예제 #4
0
    def get_day_quotes(self, ticker, timestamp):
        """Collects all quotes from the day of the market timestamp."""

        polygon_client = PolygonClient(POLYGON_API_KEY)
        quotes = []

        # The timestamp is expected in market time.
        day_str = timestamp.strftime('%Y-%m-%d')
        try:
            response = polygon_client.stocks_equities_aggregates(
                ticker, 1, 'minute', day_str, day_str)
            results = response.results
        except AttributeError as e:
            self.logs.error(
                'Failed to request historical data for %s on %s: %s' %
                (ticker, timestamp, e))
            return None

        for result in results:
            try:
                # Parse and convert the current minute's timestamp.
                minute_timestamp = result['t'] / 1000
                minute_market_time = self.utc_to_market_time(
                    datetime.fromtimestamp(minute_timestamp))

                # Use the price at the beginning of the minute.
                price = result['o']
                if not price or price < 0:
                    self.logs.warn('Invalid price: %s' % price)
                    continue

                quote = {'time': minute_market_time, 'price': price}
                quotes.append(quote)
            except (KeyError, TypeError, ValueError) as e:
                self.logs.warn('Failed to parse result: %s' % e)

        return quotes
예제 #5
0
class Polygon(MarketData):
    def __init__(self, token=os.environ.get('POLYGON'), free=True):
        super().__init__()
        self.client = RESTClient(token)
        self.provider = 'polygon'
        self.free = free

    def obey_free_limit(self):
        if self.free and hasattr(self, 'last_api_call_time'):
            time_since_last_call = time() - self.last_api_call_time
            delay = C.POLY_FREE_DELAY - time_since_last_call
            if delay > 0:
                sleep(delay)

    def log_api_call_time(self):
        self.last_api_call_time = time()

    def get_dividends(self, **kwargs):
        def _get_dividends(symbol, timeframe='max'):
            self.obey_free_limit()
            try:
                response = self.client.reference_stock_dividends(symbol)
            except Exception as e:
                raise e
            finally:
                self.log_api_call_time()
            raw = pd.DataFrame(response.results)
            df = self.standardize_dividends(symbol, raw)
            return self.reader.data_in_timeframe(df, C.EX, timeframe)

        return self.try_again(func=_get_dividends, **kwargs)

    def get_splits(self, **kwargs):
        def _get_splits(symbol, timeframe='max'):
            self.obey_free_limit()
            try:
                response = self.client.reference_stock_splits(symbol)
            except Exception as e:
                raise e
            finally:
                self.log_api_call_time()
            raw = pd.DataFrame(response.results)
            df = self.standardize_splits(symbol, raw)
            return self.reader.data_in_timeframe(df, C.EX, timeframe)

        return self.try_again(func=_get_splits, **kwargs)

    def get_ohlc(self, **kwargs):
        def _get_ohlc(symbol, timeframe='max'):
            is_crypto = symbol.find('X%3A') == 0
            formatted_start, formatted_end = self.traveller.convert_dates(
                timeframe)
            self.obey_free_limit()
            try:
                response = self.client.stocks_equities_aggregates(
                    symbol,
                    1,
                    'day',
                    from_=formatted_start,
                    to=formatted_end,
                    unadjusted=False)
            except Exception as e:
                raise e
            finally:
                self.log_api_call_time()
            raw = response.results
            columns = {
                't': 'date',
                'o': 'open',
                'h': 'high',
                'l': 'low',
                'c': 'close',
                'v': 'volume',
                'vw': 'average',
                'n': 'trades'
            }

            df = pd.DataFrame(raw).rename(columns=columns)
            if is_crypto:
                df['date'] = pd.to_datetime(df['date'], unit='ms')
            else:
                df['date'] = pd.to_datetime(
                    df['date'], unit='ms').dt.tz_localize('UTC').dt.tz_convert(
                        C.TZ).dt.tz_localize(None)
            df = self.standardize_ohlc(symbol, df)
            return self.reader.data_in_timeframe(df, C.TIME, timeframe)

        return self.try_again(func=_get_ohlc, **kwargs)

    def get_intraday(self, **kwargs):
        def _get_intraday(symbol, min=1, timeframe='max', extra_hrs=True):
            # pass min directly into stock_aggs function as multiplier
            is_crypto = symbol.find('X%3A') == 0
            dates = self.traveller.dates_in_range(timeframe)
            if dates == []:
                raise Exception(f'No dates in timeframe: {timeframe}.')

            for idx, date in enumerate(dates):
                self.obey_free_limit()
                try:
                    response = self.client.stocks_equities_aggregates(
                        symbol,
                        min,
                        'minute',
                        from_=date,
                        to=date,
                        unadjusted=False)
                except Exception as e:
                    raise e
                finally:
                    self.log_api_call_time()

                if hasattr(response, 'results'):
                    response = response.results
                else:
                    continue

                columns = {
                    't': 'date',
                    'o': 'open',
                    'h': 'high',
                    'l': 'low',
                    'c': 'close',
                    'v': 'volume',
                    'vw': 'average',
                    'n': 'trades'
                }
                df = pd.DataFrame(response).rename(columns=columns)
                if is_crypto:
                    df['date'] = pd.to_datetime(df['date'], unit='ms')
                else:
                    df['date'] = pd.to_datetime(
                        df['date'],
                        unit='ms').dt.tz_localize('UTC').dt.tz_convert(
                            C.TZ).dt.tz_localize(None)
                filename = self.finder.get_intraday_path(
                    symbol, date, self.provider)
                df = self.standardize_ohlc(symbol, df, filename)
                df = df[df[C.TIME].dt.strftime(C.DATE_FMT) == date]
                yield df

        return self.try_again(func=_get_intraday, **kwargs)
예제 #6
0
                'low': 'Low',
                'close': 'Close',
            })
    elif False:
        pu = "https://api.polygon.io/v2/aggs/ticker/AAPL/range/1/week/2019-01-01/2019-02-01?sort=asc&apiKey=rmr_K5BO36nfgC_N6qpPNt95kMY_Z3F_iX_0aC"

        if freq == "H" or freq.startswith("H"):
            timespan = "hour"
            multiplier = int(freq.replace("H", ""))
        elif freq == "D" or freq.startswith("D"):
            timespan = "day"
            multiplier = int(freq.replace("D", ""))
        elif freq == "M" or freq.startswith("M"):
            timespan = "minute"
            multiplier = int(freq.replace("M", ""))
        res = pgo.stocks_equities_aggregates(ticker, multiplier, timespan,
                                             startDate, endDate)

        df = pd.DataFrame(res.results)
        df = df.rename(columns={
            't': 'Date_Time',
            'o': 'Open',
            'h': 'High',
            'l': 'Low',
            'c': 'Close',
        })
        df['Date_Time'] = df['Date_Time'].map(lambda n: int(n / 1000))
        df['Date_Time'] = pd.to_datetime(df['Date_Time'], unit="s")
    else:
        if freq == "H" or freq.startswith("H"):
            p = freq.replace("H", "") + "h"
        elif freq == "D" or freq.startswith("D"):