def answer(self, cardinal, user, channel, msg): if not (msg.endswith("?") and len(msg.split()) > 1): cardinal.sendMsg(channel, "Was that a question?") return cardinal.sendMsg( channel, "Let me dig deep into the waters of life, and find your answer." ) yield sleep(2) cardinal.sendMsg(channel, "Hmmm...") yield sleep(2) cardinal.sendMsg(channel, self._get_random_answer())
def tick(self): """Send a message with daily stock movements""" # Start the timer for the next tick -- do this first, as the rest of # this function may take time. While that's OK, and it shouldn't take # anywhere close to 15 minutes, reloading the plugin during that time # could result in close() cancelling the event, and then wait() getting # called from the old (reloaded) instance. self.wait() # If it's after 4pm ET or before 9:30am ET on a weekday, or if it's # a weekend (Saturday or Sunday), don't tick, just wait. now = est_now() # Determine if the market is currently open is_market_open = not ( (now.weekday() >= 5) or (now.hour < 9 or now.hour >= 17) or (now.hour == 9 and now.minute < 30) or (now.hour == 16 and now.minute > 0)) # Determine if this is the market opening or market closing is_open = now.hour == 9 and now.minute == 30 is_close = now.hour == 16 and now.minute == 0 # Determine if we should do predictions after sending ticker should_do_predictions = True \ if is_market_open and (is_open or is_close) \ else False # If there are no stocks to send in the ticker, or no channels to send # them to, don't tick, just wait. should_send_ticker = is_market_open and \ self.config["channels"] and self.config["stocks"] if should_send_ticker: yield self.send_ticker() if should_do_predictions: # Try to avoid hitting rate limiting (5 calls per minute) by giving # a minute of buffer after the ticker. yield util.sleep(60) yield self.do_predictions()
def make_av_request(self, function, params=None): if params is None: params = {} params['function'] = function params['apikey'] = self.config["api_key"] params['datatype'] = 'json' retries_remaining = MAX_RETRIES while retries_remaining > 0: retries_remaining -= 1 try: r = yield deferToThread(requests.get, AV_API_URL, params=params) result = r.json() # Detect rate limiting if 'Note' in result and 'call frequency' in result['Note']: raise ThrottledException(result['Note']) except Exception: self.logger.exception( "Failed to make request to AV API - " "retries remaining: {}".format(retries_remaining)) # Raise the exception if we're out of retries if retries_remaining == 0: raise # If we succeeded, don't retry else: break # Otherwise, sleep 15 seconds to avoid rate limits before retrying yield util.sleep(RETRY_WAIT) continue defer.returnValue(result)
def do_predictions(self): # Loop each prediction, grouped by symbols to avoid rate limits with self.db() as db: predicted_symbols = list(db['predictions'].keys()) for symbol in predicted_symbols: try: data = yield self.get_daily(symbol) actual = data['close'] except Exception: self.logger.exception( "Failed to fetch information for symbol {} -- skipping". format(symbol)) for channel in self.config["channels"]: self.cardinal.sendMsg( channel, "Error with predictions for symbol {}.".format(symbol)) continue # Loop each nick's prediction, and look for the closest prediction # for the current symbol closest_prediction = None closest_delta = None closest_nick = None with self.db() as db: predictions = db['predictions'][symbol] del db['predictions'][symbol] for nick, prediction in list(predictions.items()): # Check if this is the closest guess for the symbol so far delta = abs(actual - prediction['prediction']) if not closest_delta or delta < closest_delta: closest_prediction = prediction['prediction'] closest_delta = delta closest_nick = nick self.send_prediction( nick, symbol, prediction, actual, ) market_open_close = 'open' if market_is_open() else 'close' for channel in self.config["channels"]: self.cardinal.sendMsg( channel, "{} had the closest guess for \x02{}\x02 out of {} " "predictions with a prediction of {} ({}) " "compared to the actual {} of {} ({}).".format( closest_nick, symbol, len(predictions), closest_prediction, colorize( get_delta(closest_prediction, prediction['base'])), market_open_close, actual, colorize(get_delta(actual, prediction['base'])), )) # Try to avoid hitting rate limiting (5 calls per minute) by # only checking predictions of 4 symbols per minute yield util.sleep(15)
def do_predictions(self): # Loop each prediction, grouped by symbols to avoid rate limits with self.db() as db: # TODO will this generator still work if it's iterated outside the # context manager? predicted_symbols = list(db['predictions'].keys()) for symbol in predicted_symbols: try: data = yield self.get_daily(symbol) # this is not 100% accurate as to the value at open... it's # just a value close to the open, iex cloud doesn't let us get # at the true open without paying actual = data['price'] except Exception: self.logger.exception( "Failed to fetch information for symbol {} -- skipping" .format(symbol)) for channel in self.config["channels"]: self.cardinal.sendMsg( channel, "Error with predictions for symbol {}." .format(symbol)) continue # Loop each nick's prediction, and look for the closest prediction # for the current symbol closest_prediction = None closest_delta = None closest_nick = None with self.db() as db: predictions = db['predictions'][symbol] del db['predictions'][symbol] for nick, prediction in list(predictions.items()): # Check if this is the closest guess for the symbol so far delta = abs(actual - prediction['prediction']) if not closest_delta or delta < closest_delta: closest_prediction = prediction['prediction'] closest_delta = delta closest_nick = nick self.send_prediction( nick, symbol, prediction, actual, ) market_open_close = 'open' if market_is_open() else 'close' for channel in self.config["channels"]: self.cardinal.sendMsg( channel, "{} had the closest guess for {} out of {} " "predictions with a prediction of {:.2f} ({}) " "compared to the actual {} of {:.2f} ({}).".format( closest_nick, F.bold(symbol), len(predictions), closest_prediction, colorize(get_delta(closest_prediction, prediction['base'])), market_open_close, actual, colorize(get_delta(actual, prediction['base'])), )) # Try to avoid hitting rate limiting (5 calls per minute) by # only checking predictions of 4 symbols per minute yield util.sleep(15)
def test_sleep(): now = datetime.datetime.now() yield util.sleep(1) delta = datetime.datetime.now() - now assert delta.seconds == 1