def _build_url(self, exchange: str, symbols: List[str], start_epoch_s: float, end_epoch_s: float) -> str: """ Build url from parameters and api key """ start_str = IntuitiveDateConverter.to_day_str(start_epoch_s) end_datetime = IntuitiveDateConverter.to_datetime(end_epoch_s) end_datetime += timedelta(days=1) end_str = IntuitiveDateConverter.to_day_str(end_datetime) symbols_str = ','.join(symbols) url = f'https://api.twelvedata.com/time_series?exchange={exchange}&symbol={symbols_str}&interval=1day&' \ f'start_date={start_str}&end_date={end_str}&apikey={self.api_key}' return url
def _build_url(self, symbol: str, start_epoch_s: float, end_epoch_s: float) -> str: """ Build url from parameters and api key """ unit_str = 'day' range_str = '1' start_str = IntuitiveDateConverter.to_day_str(start_epoch_s) end_str = IntuitiveDateConverter.to_day_str(end_epoch_s) url = f'https://api.polygon.io/v2/aggs/ticker/{symbol}/range/{range_str}/{unit_str}/{start_str}/{end_str}?' \ f'apiKey={self.api_key}' return url
def run(self): all_timestamps = self.register.get_all_timestamps() for epoch_s in all_timestamps: for trader_id in range(len(self.trader_ensembles)): trader_ensemble = self.trader_ensembles[trader_id] self.trader_ensembles[trader_id].execute( epoch_s, self.register) net_worth_mean, net_worth_median, net_worth_sd = \ trader_ensemble.performance.get_net_worth_estimate(epoch_s) cash_mean, cash_median, cash_sd = trader_ensemble.performance.get_cash_estimate( epoch_s) date = IntuitiveDateConverter.to_day_str(epoch_s) self.campaign_recorder.record( date, trader_id, self.campaign_recorder.METRIC_NET_WORTH_MEAN, net_worth_mean) self.campaign_recorder.record( date, trader_id, self.campaign_recorder.METRIC_NET_WORTH_MEDIAN, net_worth_median) self.campaign_recorder.record( date, trader_id, self.campaign_recorder.METRIC_NET_WORTH_SD, net_worth_sd) self.campaign_recorder.record( date, trader_id, self.campaign_recorder.METRIC_CASH_MEAN, cash_mean) self.campaign_recorder.record( date, trader_id, self.campaign_recorder.METRIC_CASH_MEDIAN, cash_median) self.campaign_recorder.record( date, trader_id, self.campaign_recorder.METRIC_CASH_SD, cash_sd)
def __init__(self, data_ingest_manager: DataIngestManager, traders: List[Trader]) -> List: self.data_ingest_manager = data_ingest_manager self.traders = traders self.today_day_str = IntuitiveDateConverter.to_day_str(datetime.now()) self.today_epoch_s = IntuitiveDateConverter.to_epoch_s( self.today_day_str)
def run(self, candidates: List[Stock], current_holdings: List[Stock]): self.today_day_str = IntuitiveDateConverter.to_day_str(datetime.now()) self.today_epoch_s = IntuitiveDateConverter.to_epoch_s( self.today_day_str) all_stocks = candidates + current_holdings register = self._populate_register(all_stocks) signals = self.apply_traders(register, candidates, current_holdings) return signals
def _run_and_evaluate_to_day_str(self, conversion_input: object, expected_output_type: type, expected_output_value: object) -> None: idc = IntuitiveDateConverter() actual_output = idc.to_day_str(conversion_input) actual_output_type = type(actual_output) self.assertEqual(expected_output_type, actual_output_type) self.assertEqual(expected_output_value, actual_output)
def run(self): all_timestamps = self.register.get_all_timestamps() for epoch_s in all_timestamps: self.trader_ensemble.execute(epoch_s, self.register) net_worth_mean, net_worth_median, net_worth_sd = \ self.trader_ensemble.performance.get_net_worth_estimate(epoch_s) cash_mean, cash_median, cash_sd = \ self.trader_ensemble.performance.get_cash_estimate(epoch_s) date = IntuitiveDateConverter.to_day_str(epoch_s) print( f'{date}, net worth: {net_worth_mean} +- {2 * net_worth_sd} [median: {net_worth_median}], ' f'cash: {cash_mean} +- {2 * cash_sd} [median: {cash_median}]')
def determine_buys(self, epoch_s: float, register: SymbolDayRegister) -> List[str]: """ Apply rules that trigger buy order """ stocks = list(register.keys()) random.shuffle(stocks) to_buy = list() for stock in stocks: buy_flag = True prices = [None] * (self.n_crash + 1) for i in range(self.n_crash): close_today = register.get_close(stock, epoch_s, -i) if close_today is None: buy_flag = False break close_yesterday = register.get_close(stock, epoch_s, -i - 1) if close_yesterday is None: buy_flag = False break gain = 100 * (close_today / close_yesterday - 1) if gain > self.gain_crash: buy_flag = False break prices[i] = close_today prices[i + 1] = close_yesterday if buy_flag: to_buy.append(stock) date = IntuitiveDateConverter.to_day_str(epoch_s) print( f'Identified BUY flag: {date} : {stock.to_str()} : {prices}' ) if self.logger is not None: message = f'Identified BUY flag: {date} : {stock.to_str()} : {prices}' self.logger.log_message(message) if len(to_buy) >= self.n_buy_per_day: break return to_buy
def determine_sells(self, epoch_s: float, register: SymbolDayRegister) -> List[str]: """ Apply rules that trigger sell order """ stocks = self.holdings.keys() to_sell = list() for stock in stocks: sell_flag = True prices = [None] * (self.n_down + 1) for i in range(self.n_down): close_today = register.get_close(stock, epoch_s, -i) if close_today is None: sell_flag = False break close_yesterday = register.get_close(stock, epoch_s, -i - 1) if close_yesterday is None: sell_flag = False break gain = 100 * (close_today / close_yesterday - 1) if gain > self.gain_down: sell_flag = False break prices[i] = close_today prices[i + 1] = close_yesterday if sell_flag: to_sell.append(stock) date = IntuitiveDateConverter.to_day_str(epoch_s) if self.logger is not None: message = f'Identified SELL flag: {date} : {stock.to_str()} : {prices}' self.logger.log_message(message) return to_sell
def get_technical_indicator(self, stock: Stock, indicator_name: str, start_epoch_s: float, end_epoch_s: float) -> List[Moment]: start_date = IntuitiveDateConverter.to_day_str(start_epoch_s) end_datetime = IntuitiveDateConverter.to_datetime(end_epoch_s) end_datetime += timedelta(days=1) end_date = IntuitiveDateConverter.to_day_str(end_datetime) request_url = f'https://api.twelvedata.com/{indicator_name.lower()}?symbol=' \ f'{stock.symbol}&exchange={stock.exchange}&interval=1day&start_date=' \ f'{start_date}&end_date={end_date}&apikey={self.api_key}' for _ in range(MAX_RETRIES): try: print( f'API call for technical indicator {indicator_name.lower()} for {stock.to_str()}' ) response = requests.get(request_url) except ChunkedEncodingError: print( f'intermittent ChunkedEncodingError. Retrying in {RETRY_PAUSE_CHUNK_ERROR}s' ) time.sleep(RETRY_PAUSE_CHUNK_ERROR) print('retrying') continue except Exception as e: print("Stopping retry loop because of un-handled error") raise e else: content = response.content content = json.loads(content) if 'code' in content.keys(): if content['code'] == ERROR_CODE_TOO_MANY_REQUESTS: print( f'Too many requests. Pausing for {RETRY_PAUSE_S} seconds before retrying.' ) time.sleep(RETRY_PAUSE_S) continue if 'values' not in content: print('unexpected response:') print(content) break moments = list() if 'values' not in content: return moments for item in content['values']: epoch_s = IntuitiveDateConverter.to_epoch_s(item['datetime']) for k, v in item.items(): if k == 'datetime': continue if k == indicator_name: moment_data = { 'epoch_s': epoch_s, 'exchange': stock.exchange, 'symbol': stock.symbol, indicator_name: item[k] } moment = Moment(**moment_data) moments.append(moment) else: moment_data = { 'epoch_s': epoch_s, 'exchange': stock.exchange, 'symbol': stock.symbol, f'{indicator_name}_{k}': item[k] } moment = Moment(**moment_data) moments.append(moment) return moments