def logoff(): """Robinhood logoff""" robinhood.logout()
def test_login_failed(self): r.logout() profile = r.load_account_profile(info=None) assert profile
def run_traderbot(): """Main function for this module. Spawns a thread for each ticker that trades on that symbol for the duration of the day.""" # get info from config file and log in global USERNAME, PASSWORD, PAPER_TRADING, TIME_ZONE global START_OF_DAY, END_OF_DAY, TRADE_LIMIT, CONFIG CONFIG = get_json_dict() USERNAME = CONFIG["username"] PASSWORD = CONFIG["password"] MAX_LOSS_PERCENT = CONFIG["max-loss-percent"]/100.0 TAKE_PROFIT_PERCENT = CONFIG["take-profit-percent"]/100.0 SPEND_PERCENT = CONFIG["spend-percent"]/100.0 PAPER_TRADING = CONFIG["paper-trading"] TIME_ZONE = CONFIG.get("time-zone-pandas-market-calendars", "America/New_York") full_start_time_str = CONFIG.get("start-of-day", "09:30") + "={}".format(TIME_ZONE) full_end_time_str = CONFIG.get("end-of-day", "16:00") + "={}".format(TIME_ZONE) START_OF_DAY = datetime.strptime(full_start_time_str, "%H:%M=%Z").time() END_OF_DAY = datetime.strptime(full_end_time_str, "%H:%M=%Z").time() TRADE_LIMIT = CONFIG.get("max-trades-per-day", None) BUDGET = CONFIG.get("budget", None) END_TIME_STR = CONFIG.get("end-time", None) START_TIME_STR = CONFIG.get("start-time", None) ALPACA_KEY = CONFIG["alpaca-api-key"] ALPACA_SECRET_KEY = CONFIG["alpaca-secret-key"] STRATEGIES_DICT = CONFIG["strategies"] HISTORY_SIZE = CONFIG.get("history-len", 16) if not ((HISTORY_SIZE & (HISTORY_SIZE-1) == 0) and HISTORY_SIZE != 0): raise ConfigException("history-len must be a power of two, {} was entered".format(HISTORY_SIZE)) TREND_SIZE = CONFIG.get("trend-len", 3) if TREND_SIZE > HISTORY_SIZE: raise ConfigException("trend-len must be less than or equal to history-len") IS_INSTANT_ACCT = CONFIG.get("instant", False) zero_time = timedelta() login = log_in_to_robinhood() # get list of unique tickers and enforce legality of strategies kv in the config ALL_TICKERS = [] for st in STRATEGIES_DICT: enforce_keys_in_dict(['strategy', 'tickers'], st) enforce_strategy_dict_legal(st['strategy']) ALL_TICKERS.extend(st['tickers']) ALL_TICKERS = list(set(ALL_TICKERS)) # generate parameters so we don't get flagged START_OF_DAY, END_OF_DAY, TRADE_LIMIT = generate_humanlike_parameters() datetime_fmt_str = '%H:%M:%S' if END_TIME_STR is not None: END_OF_DAY = datetime.strptime(END_TIME_STR, datetime_fmt_str).time() if START_TIME_STR is not None: START_OF_DAY = datetime.strptime(START_TIME_STR, datetime_fmt_str).time() print_with_lock("param: will start trading today at:", START_OF_DAY) print_with_lock("param: will stop trading today at:", END_OF_DAY) print_with_lock("param: will make a maximum of {} trades today".format(TRADE_LIMIT)) # busy-spin until market open block_until_market_open() # these variables are shared by each trading thread. they are written by this # main traderbot thread, and read by each trading thread individually market_data = MarketData(ALL_TICKERS, ALPACA_KEY, ALPACA_SECRET_KEY, HISTORY_SIZE, TREND_SIZE) buying_power = BuyingPower(SPEND_PERCENT, IS_INSTANT_ACCT, BUDGET) trade_capper = TradeCapper(TRADE_LIMIT) # now that market open is today, update EOD for time checking now = datetime.now() END_OF_DAY = datetime(now.year, now.month, now.day, END_OF_DAY.hour, END_OF_DAY.minute, END_OF_DAY.second, END_OF_DAY.microsecond) market_time = MarketTime(END_OF_DAY) reports = Reports() # spawn thread for each ticker threads = [] for st in STRATEGIES_DICT: strategy_dict = st['strategy'] tickers = st['tickers'] for ticker in tickers: print_with_lock("initializing thread {} with strategy configuration {}".format(ticker, strategy_dict)) strategy = strategy_factory(strategy_dict, market_data, ticker) if not strategy.is_relevant(): # don't add irrelevant tickers to the threadpool. # long term could figure out how to remove this # from the market data object too continue threads.append(TradingThread(ticker, market_data, market_time, buying_power, trade_capper, strategy, reports, TAKE_PROFIT_PERCENT, MAX_LOSS_PERCENT, PAPER_TRADING)) # busy spin until we decided to start trading block_until_start_trading() # update before we start threads to avoid mass panic market_data.start_stream() market_time.update() # start all threads for t in threads: t.start() # update the timer in the main thread while market_time.is_time_left_to_trade(): market_time.update() # wait for all threads to finish for t in threads: t.join() # now pretty print reports reports.print_eod_reports() # tidy up after ourselves r.logout() print_with_lock("logged out user {}".format(USERNAME))
# Query last trading price for each stock ticker lastPrice = r.get_quotes(tickers, "last_trade_price") # Calculate the profit per share profitPerShare = [ float(lastPrice[i]) - float(prevClose[i]) for i in range(len(tickers)) ] # Calculate the percent change for each stock ticker percentChange = [ 100.0 * profitPerShare[i] / float(prevClose[i]) for i in range(len(tickers)) ] # Calcualte your profit for each stock ticker profit = [profitPerShare[i] * quantities[i] for i in range(len(tickers))] # Combine into list of lists, for sorting tickersPerf = list(zip(profit, percentChange, tickers)) tickersPerf.sort(reverse=True) print("My Positions Performance:") print("Ticker | DailyGain | PercentChange") for item in tickersPerf: print("%s %f$ %f%%" % (item[2], item[0], item[1])) print("Net Gain:", sum(profit)) r.logout()
def teardown_class(cls): r.logout()
def main(): # login to Robinhood robinhood_login() logger.info('Robinhood login successful.') market_opens, market_closes = get_next_market_open_hours() logger.info('Market opens {} and closes {}.'.format( market_opens, market_closes)) current_time = parser.parse(datetime.now(timezone.utc).isoformat()) daily_open_positions = 0 # while market is open, execute trading strategy while (current_time >= market_opens) & (current_time < market_closes) & ( daily_open_positions < max_daily_open_positions): # get nearest Friday expiration nearest_friday_expiration = find_nearest_weekday_date( days_until_expiration_range=days_until_expiration_range, weekday_num=weekday_num, ) # get implied volatility data iv_data = get_implied_volatility_data() # filter to tickers with high IV and volume ticker_list = iv_data.loc[ (iv_data.optionsImpliedVolatilityRank1y > iv_rank_min) & (iv_data.optionsImpliedVolatilityPercentile1y > iv_percentile_min) & (iv_data.optionsTotalVolume > total_option_volume_min)]['symbol'].tolist() # get recent open positions remove_tickers = get_recent_open_option_tickers(option_type, day_lag) # remove tickers of positions from list for _ticker in remove_tickers: if _ticker in ticker_list: ticker_list.remove(_ticker) # create put credit spread trades dataframe put_credit_spread_trades = pd.DataFrame( data=[], columns=[ 'symbol', 'type', 'expiration_date', 'short_strike_price', 'short_mark_price', 'short_ask_price', 'short_bid_price', 'short_spread', 'short_volume', 'short_open_interest', 'short_delta', 'short_gamma', 'short_rho', 'short_theta', 'short_vega', 'long_strike_price', 'long_mark_price', 'long_ask_price', 'long_bid_price', 'long_spread', 'long_volume', 'long_open_interest', 'long_delta', 'long_gamma', 'long_rho', 'long_theta', 'long_vega', 'trade_strike_width', 'trade_limit_price', 'trade_spread', 'trade_spread_ratio', 'avg_trade_volume', 'trade_expected_dollar_return', 'trade_expected_percent_return' ], ) # sort through each ticker looking for possible trades for _ticker in ticker_list: try: expiration_option_chain_data = pd.DataFrame( rs.options.find_options_by_expiration( inputSymbols=_ticker, expirationDate=nearest_friday_expiration, optionType='put', )) except TypeError: expiration_option_chain_data = pd.DataFrame() if not expiration_option_chain_data.empty: # different from call script short_put_df = expiration_option_chain_data.loc[ (abs( expiration_option_chain_data.delta.astype(float) + target_delta) <= delta_tolerance) & (expiration_option_chain_data.volume.astype(float) >= option_volume_min) & (expiration_option_chain_data.open_interest.astype(float) >= option_open_interest_min)].copy() if short_put_df.shape[0] > 0: if short_put_df.shape[0] > 1: short_put_df.sort_values(by='volume', ascending=False, inplace=True) short_put_df.reset_index(drop=True, inplace=True) short_put_df = short_put_df.loc[short_put_df.index == 0] _symbol = short_put_df['symbol'].astype(str).values[0] _type = 'put credit spread' _expiration_date = short_put_df['expiration_date'].astype( str).values[0] _short_strike_price = short_put_df['strike_price'].astype( float).values[0] _short_mark_price = short_put_df['mark_price'].astype( float).values[0] _short_ask_price = short_put_df['ask_price'].astype( float).values[0] _short_bid_price = short_put_df['bid_price'].astype( float).values[0] _short_spread = _short_ask_price - _short_bid_price _short_volume = short_put_df['volume'].astype( float).values[0] _short_open_interest = short_put_df[ 'open_interest'].astype(float).values[0] _short_delta = short_put_df['delta'].astype( float).values[0] _short_gamma = short_put_df['gamma'].astype( float).values[0] _short_rho = short_put_df['rho'].astype(float).values[0] _short_theta = short_put_df['theta'].astype( float).values[0] _short_vega = short_put_df['vega'].astype(float).values[0] # to do: cast expiration_option_chain_data columns to float type expiration_option_chain_data[ 'strike_price'] = expiration_option_chain_data[ 'strike_price'].astype(float) # different from call script long_put_df = expiration_option_chain_data.loc[ expiration_option_chain_data['strike_price'].astype( float) < _short_strike_price].sort_values( by='strike_price', ascending=False).head(1) _long_strike_price = long_put_df['strike_price'].astype( float).values[0] _long_mark_price = long_put_df['mark_price'].astype( float).values[0] _long_ask_price = long_put_df['ask_price'].astype( float).values[0] _long_bid_price = long_put_df['bid_price'].astype( float).values[0] _long_spread = _long_ask_price - _long_bid_price _long_volume = long_put_df['volume'].astype( float).values[0] _long_open_interest = long_put_df['open_interest'].astype( float).values[0] _long_delta = long_put_df['delta'].astype(float).values[0] _long_gamma = long_put_df['gamma'].astype(float).values[0] _long_rho = long_put_df['rho'].astype(float).values[0] _long_theta = long_put_df['theta'].astype(float).values[0] _long_vega = long_put_df['vega'].astype(float).values[0] # different from call script _trade_strike_width = -1 * (_long_strike_price - _short_strike_price) _trade_limit_price = _short_mark_price - _long_mark_price _trade_spread = _short_ask_price - _long_bid_price _trade_spread_ratio = _trade_spread / _trade_strike_width _avg_trade_volume = (_short_volume + _long_volume) / 2 # different from call script _trade_expected_dollar_return = ( 1 + _short_delta) * _trade_limit_price _trade_expected_percent_return = _trade_expected_dollar_return / ( _trade_strike_width - _trade_limit_price) put_credit_spread_trades.loc[-1] = [ _symbol, _type, _expiration_date, _short_strike_price, _short_mark_price, _short_ask_price, _short_bid_price, _short_spread, _short_volume, _short_open_interest, _short_delta, _short_gamma, _short_rho, _short_theta, _short_vega, _long_strike_price, _long_mark_price, _long_ask_price, _long_bid_price, _long_spread, _long_volume, _long_open_interest, _long_delta, _long_gamma, _long_rho, _long_theta, _long_vega, _trade_strike_width, _trade_limit_price, _trade_spread, _trade_spread_ratio, _avg_trade_volume, _trade_expected_dollar_return, _trade_expected_percent_return, ] put_credit_spread_trades.index += 1 # identify possible trades to execute, if any possible_put_credit_spread_trades = put_credit_spread_trades.loc[ (put_credit_spread_trades.trade_strike_width <= max_strike_width) & (put_credit_spread_trades.trade_expected_percent_return > min_percent_return)].sort_values(by='avg_trade_volume', ascending=True) # select a trade to execute, if any if possible_put_credit_spread_trades.shape[0] > 0: put_credit_spread_trade = possible_put_credit_spread_trades.iloc[ -1] # set option orders as list put_credit_spread_open_order_list = [ { 'expirationDate': put_credit_spread_trade['expiration_date'], 'strike': put_credit_spread_trade['short_strike_price'], 'optionType': 'put', 'effect': 'open', 'action': 'sell', }, { 'expirationDate': put_credit_spread_trade['expiration_date'], 'strike': put_credit_spread_trade['long_strike_price'], 'optionType': 'put', 'effect': 'open', 'action': 'buy', }, ] # send order to Robinhood put_credit_spread_open_order_receipt = rs.order_option_credit_spread( price=put_credit_spread_trade['trade_limit_price'].round(2), symbol=put_credit_spread_trade['symbol'], quantity=1, spread=put_credit_spread_open_order_list, timeInForce='gfd', ) # check order status updated_put_credit_spread_open_order_receipt = rs.get_option_order_info( order_id=put_credit_spread_open_order_receipt['id'], ) # check until trade is executed or canceled check_for_trade_execution = True while check_for_trade_execution: updated_put_credit_spread_open_order_receipt = rs.get_option_order_info( order_id=put_credit_spread_open_order_receipt['id'], ) if updated_put_credit_spread_open_order_receipt[ 'state'] == 'filled': trade_filled = True check_for_trade_execution = False elif updated_put_credit_spread_open_order_receipt[ 'state'] == 'cancelled': trade_filled = False check_for_trade_execution = False else: # sleep for 5 minutes sleep(300) if trade_filled: # send closing trade order to Robinhood if updated_put_credit_spread_open_order_receipt[ 'state'] == 'filled': put_credit_spread_close_order_list = [ { 'expirationDate': put_credit_spread_trade['expiration_date'], 'strike': put_credit_spread_trade['short_strike_price'], 'optionType': 'put', 'effect': 'close', 'action': 'buy', }, { 'expirationDate': put_credit_spread_trade['expiration_date'], 'strike': put_credit_spread_trade['long_strike_price'], 'optionType': 'put', 'effect': 'close', 'action': 'sell', }, ] put_credit_spread_close_order_receipt = rs.order_option_debit_spread( price=(put_credit_spread_trade['trade_limit_price'] * profit_target_percent).round(2), symbol=put_credit_spread_trade['symbol'], quantity=1, spread=put_credit_spread_close_order_list, timeInForce='gtc', ) put_credit_spread_logging = pd.read_csv( trade_logging_file_path) put_credit_spread_logging_new_trade = pd.DataFrame( put_credit_spread_trade).T.round(6) for _col in put_credit_spread_logging_new_trade.columns: if _col not in [ 'index', 'symbol', 'type', 'expiration_date' ]: put_credit_spread_logging_new_trade[ _col] = put_credit_spread_logging_new_trade[ _col].astype(float).round(6) put_credit_spread_logging_new_trade[ 'trade_open_id'] = put_credit_spread_open_order_receipt[ 'id'] put_credit_spread_logging_new_trade[ 'trade_close_id'] = put_credit_spread_close_order_receipt[ 'id'] if 'index' in put_credit_spread_logging_new_trade.columns: put_credit_spread_logging_new_trade.drop(columns=['index'], inplace=True) put_credit_spread_logging = pd.concat([ put_credit_spread_logging, put_credit_spread_logging_new_trade ]) put_credit_spread_logging.drop_duplicates(inplace=True) put_credit_spread_logging.to_csv(trade_logging_file_path, index=False) daily_open_positions += 1 # delay to prevent overwhelming Robinhood API logger.info('Sleep for 300 seconds.') sleep(300) # get new current time current_time = parser.parse(datetime.now(timezone.utc).isoformat()) pass # logout while not trading rs.logout() logger.info('Robinhood logout successful.') # pause trading if max daily open positions are reached if daily_open_positions >= max_daily_open_positions: logger.info('Max daily open positions reached. Sleep for {}.'.format( timedelta(seconds=23400))) sleep(23400) # seconds until next market open wait_time = max(seconds_until_market_open(market_opens), 0) # require login at least once per day to avoid error wait_time = wait_time / 4 logger.info('Market closed. Waiting {}.'.format( timedelta(seconds=wait_time))) sleep(wait_time)
if __name__ == '__main__': args = parser.parse_args() RH_UNAME = os.environ.get("robinhood_username") RH_PWD = os.environ.get("robinhood_password") totp = pyotp.TOTP("authy").now() lg = rh.login(username=RH_UNAME, password=RH_PWD, mfa_code=totp) file_name = None dir_name = None if args.name: try: dir_name = os.path.dirname(args.name) file_name = args.name.split(dir_name)[1][1:] except: pass if args.type == 'crypto': export_crypto(dir_name=dir_name, file_name=file_name, rh=rh) elif args.type == 'stocks': export_stocks(dir_name=dir_name, file_name=file_name, rh=rh) elif args.type == 'both' or args.type == '': export_crypto(dir_name=dir_name, file_name=file_name, rh=rh) export_stocks(dir_name=dir_name, file_name=file_name, rh=rh) else: print("Please specify valid type") rh.logout() print('Done!')
def logout(): r.logout()
def logoff(): robinhood.logout()
def MFALogoff(self): """ Log off from robinhood account """ rs.logout() print(f"{bColors.OKGREEN}Info: Logoff successful.{bColors.ENDC}")