def lineup_traders(self, tickers): global ml count = 1 for ticker in tickers: self.traders.append(Trader(count, ticker, self.account)) Notify.info(f"Successfully connected Trader #{count} to {ticker}", delay=0.01) count += 1 self.logger.info("Trader lineup complete") print("")
def get_stocks(stocks_temp, prev_data, key): if (not key in prev_data): raise Exception(f"Missing key '{key}' in prev_data") for ticker in prev_data[key]: stock_name, stock_ex = ticker.split(".") if stock_name in stocks_temp: Notify.fatal("Cannot buy and sell the same stock.") quit(0) stocks_temp[stock_name] = stock_ex
def start_trading(self, Tmode=False): global ml now = datetime.datetime.now(TZ) Notify.info("Trading has begun") self.logger.info("Trading has begun") count = 1 if not Tmode: while now.time() < self.pack_up or self.is_dev_mode: try: for trader in self.traders: trader.run() self.logger.info(f"Completed round {count}") sleep(self.period) except Exception as e: Notify.fatal("Trading has been aborted") self.logger.critical( "Trade abort due to unexpected error : ", e) quit(0) finally: now = datetime.datetime.now(TZ) count += 1 else: Notify.info("Confirming access to live stock price...") self.logger.info("Confirming access to live stock price...") for trader in self.traders: try: get_live_price(trader.ticker) except Exception as e: Notify.fatal( "Error in fetching live stock price. Aborting") self.logger.critical( "Error in fetching live stock price : ", e)
def start_trading(self, Tmode=False): global ml now = datetime.datetime.now(TZ) Notify.info("Trading has begun") ml.info("Trading has begun") count = 1 if not Tmode: while now.time() < PACK_UP or DEV_MODE: try: for trader in self.traders: trader.run() ml.info("Completed round #", count) sleep(PERIOD_INTERVAL) except Exception as e: Notify.fatal("Trading has been aborted") ml.critical("Trade abort due to unexpected error : ", e) quit(0) finally: now = datetime.datetime.now(TZ) count += 1 else: Notify.info("Confirming access to live stock price...") ml.info("Confirming access to live stock price...") for trader in self.traders: try: get_live_price(trader.ticker) except Exception as e: Notify.fatal( "Error in fetching live stock price. Aborting") ml.critical("Error in fetching live stock price : ", e)
def get_initial_data(self): try: self.price.append(get_live_price(self.ticker)) self.logger.debug("Successfully fetched live price") except SysCallError: Notify.warn( f"[Trader #{self.number} {self.ticker}]: Encountered SysCallError while initialising parameters, trying recursion" ) self.logger.warning("Encountered SysCallError, trying recursion") self.get_initial_data() except Exception as e: Notify.warn( f"[Trader #{self.number} {self.ticker}]: Exception in getting initial data, trying recursion" ) self.logger.error("Trying recursion due to uncommon Exception : ", e) self.get_initial_data()
def update_price(self): try: new_price = get_live_price(self.ticker) self.price.append(new_price) self.logger.info( "Successfully fetched price, local database updated") except SysCallError: Notify.warn( f"[Trader #{self.number} {self.ticker}] : Encountered SysCallError in updating price, trying recursion" ) self.logger.warning( "Encountered SysCallError while fetching live price, trying recursion" ) self.update_price() except Exception as e: Notify.warn( f"[Trader #{self.number} {self.ticker}] : Exception in updating price, trying recursion" ) self.logger.error( "Trying recursion, encountered uncommon exception : ", e) self.update_price()
def init_traders(self, Tmode=False): global ml Notify.info("Traders are in Observation phase") self.logger.info("Traders entered Observation Phase") if not Tmode: self.print_progress_bar(0, 80, prefix='Progress:', suffix='Complete', length=40) for i in range(DATA_LIMIT): for trader in self.traders: trader.get_initial_data() self.print_progress_bar(i + 1, 80, prefix='\tProgress:', suffix='Complete', length=40) sleep(self.period) Notify.info("\tStatus : Complete") self.logger.info("Observation Phase complete") print("")
def __del__(self): # load previous day's data prev_data = json.loads(open("..\\user_info.json").read()) username = prev_data['username'] # debug account_balance_prev = prev_data["account_balance"] # get new data from trader's database account_balance_new = account_balance_prev * ( 1 - self.feasible_percent) + self.account profit = account_balance_new - account_balance_prev # set up new data new_data = dict() new_data['username'] = username new_data["account_balance"] = account_balance_new new_data["stocks_to_sell"] = dict() new_data["stocks_to_buy_back"] = dict() # grab data from trader database for trader in self.traders: # check owned stocks if trader.IN_LONG_TRADE: new_data["stocks_to_sell"][trader.ticker] = { "buffer_price": trader.price_for_buffer } # check owed stocks if trader.IN_SHORT_TRADE: new_data["stocks_to_buy_back"][trader.ticker] = { "buffer_price": trader.price_for_buffer } # save trader database in respective files del trader # save master database with open("..\\user_info.json", "w") as fp: fp.write(json.dumps(new_data, indent=4)) # output profit Notify.info(f"\n\nNet Profit : $ {profit} \n") self.logger.info(f"\n\nNet Profit : $ {profit} \n") Notify.info(f'Stocks owned : {len(new_data["stocks_to_sell"])}') self.logger.info(f'Stocks owned : {len(new_data["stocks_to_sell"])}') Notify.info(f'Stocks sold : {len(new_data["stocks_to_buy_back"])}') self.logger.info( f'Stocks sold : {len(new_data["stocks_to_buy_back"])}')
def make_decision(self): # global ACCOUNT # update tenkan data self.tenkan_data = [] for i in range(DATA_LIMIT - 9): tenkan_src = self.price[i:i + 9] self.tenkan_data.append((max(tenkan_src) + min(tenkan_src)) / 2) # update kijun data self.kijun_data = [] for i in range(DATA_LIMIT - 26): kijun_src = self.price[i:i + 26] self.kijun_data.append((max(kijun_src) + min(kijun_src)) / 2) # update x values for senkou A and senkou B self.x5 = self.time[78:78 + DATA_LIMIT - 26] self.x6 = self.time[104:104 + DATA_LIMIT - 52] # update senkou A data self.senkou_A_data = [ (self.tenkan_data[i + 17] + self.kijun_data[i]) / 2 for i in range(DATA_LIMIT - 26) ] # update senkou B data self.senkou_B_data = [] for i in range(DATA_LIMIT - 52): senkou_B_src = self.price[i:i + 52] self.senkou_B_data.append( (max(senkou_B_src) + min(senkou_B_src)) / 2) # get Ichimoku params for comparison x = self.time[26:26 + DATA_LIMIT][-1] curr_price = self.price[-1] tenkan = self.tenkan_data[-1] kijun = self.kijun_data[-1] sen_A = self.get_value(self.senkou_A_data, self.x5, x) sen_B = self.get_value(self.senkou_B_data, self.x6, x) self.logger.info( f"Current status - Price : {curr_price}, Tenkan : {tenkan}, Kijun : {kijun}, Senkou A : {sen_A}, Senkou B : {sen_B}" ) # conditions for long trade entry # If Kumo cloud is green and current price is above kumo, strong bullish signal cond1 = (sen_A > sen_B) and (curr_price >= sen_A) if cond1: self.logger.debug("Sensing strong bullish signal") # conditions for short trade entry # If Kumo cloud is red and current price is below kumo, strong bearish signal cond2 = (sen_A < sen_B) and (curr_price <= sen_A) if cond2: self.logger.debug("Sensing strong bearish signal") # check allocated money cond3 = curr_price < self.account # IF all conditions are right, long trade entry if cond1 and not self.IN_LONG_TRADE and cond3: self.buy(curr_price, "LONG") self.price_for_buffer = curr_price self.IN_LONG_TRADE = True self.STOCKS_TO_SELL += 1 if not cond3: Notify.fatal( f"[Trader #{self.number} {self.ticker}] : Oops! Out of cash!") self.logger.critical("Trader out of cash to buy stocks!") # If all conditions are right, short trade entry if cond2 and not self.IN_SHORT_TRADE: self.sell(curr_price, "SHORT") self.price_for_buffer = curr_price self.IN_SHORT_TRADE = True self.STOCKS_TO_BUY_BACK += 1 # setup buffer for stop loss and trade exit buffer = self.price_for_buffer * BUFFER_PERCENT cond4 = abs(curr_price - kijun) >= buffer # Get stopped out as the price moves through the buffer area beyond the Kijun if self.IN_LONG_TRADE: if cond4: self.sell(curr_price, "LONG") self.IN_LONG_TRADE = False self.STOCKS_TO_SELL -= 1 if self.IN_SHORT_TRADE: if cond4 and cond3: self.buy(curr_price, "SHORT") self.IN_SHORT_TRADE = False self.STOCKS_TO_BUY_BACK -= 1 if not cond3: Notify.fatal( f"[Trader #{self.number} {self.ticker}] : Oops! Out of cash!" ) self.logger.critical("Trader out of cash to buy back stock !")
def main(): """ Main Function """ # make sure that market is open if not DEV_MODE and CHECK_MARKET: if args.t: Notify.for_input("Check Market? (y/n) : ") confirm = input().strip().lower() print("") else: confirm = "y" if is_open() or confirm == "n": pass else: Notify.fatal("Market is closed at the moment, aborting.") print("") quit(0) # else: # Notify.warn("You are in developer mode, if not intended, please quit.") # Notify.info("Press ENTER to continue, Ctrl+C to quit") # input() # allow market to settle to launch Ichimoku strategy if IDLE_DELAY == 0: Notify.info("Skipped Idle phase") else: Notify.info( f"Entered Idle phase at {datetime.datetime.now(TZ).strftime('%H:%M:%S')}" ) master_logger.info(f"Entered Idle phase") Notify.info(f"\tExpected release : after {IDLE_DELAY // 60} minutes") print("") sleep(IDLE_DELAY) master_logger.info("Idle phase complete") # find relevant stocks to focus on Notify.info("Finding stocks to focus on .....") try: stocks_to_focus = fetch_stocks() except Exception as ex: print(f'Exception was {ex}') stocks_to_focus = [] Notify.fatal( "Could not fetch relevant stocks. Verify Network connection and check logs for details." ) master_logger.critical( "Could not fetch relevant stocks, Most possibly due to network error" ) quit(0) Notify.info("\tStatus : Complete") master_logger.info("Successfully found relevant stocks") print("") # setup traders and begin trade master = Master(PERIOD_INTERVAL, master_logger, FEASIBLE_PERCENT, ACCOUNT, PACK_UP, DEV_MODE) master.validate_repo() master.lineup_traders(stocks_to_focus) master.init_traders(args.t) master.start_trading(args.t) # trading in over by this point Notify.info("Trading complete") master_logger.info("Trading complete") # initiate packup del master quit(0)
def fetch_stocks(): """ Find relevant stocks to focus on for trading Returns: Deque of tickers of relevant stocks """ global ml # url to grab data from url = f'https://finance.yahoo.com/gainers?count={NUM_OF_STOCKS_TO_SEARCH}' # request header headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36' } try: src = requests.get(url=url, headers=headers).content except Exception as e: src = None Notify.fatal( "Trade abort due to unexpected error. Check activity log for details" ) master_logger.critical("Encountered error : ", e) quit(0) # soup object of source code soup = BeautifulSoup(src, "html.parser") rows = soup.find('table').tbody.find_all('tr') # initialisations stocks_temp = dict() # check previous day's closing status prev_data = json.loads(open("database/user_info.json").read()) get_sells(stocks_temp, prev_data, "stocks_to_sell") get_buys(stocks_temp, prev_data, "stocks_to_buy_back") # set counter count = len(stocks_temp) stocks = deque() # iterate over rows in web page for tr in rows: # exit if if count == NUM_OF_STOCKS_TO_FOCUS: break else: row_data = tr.find_all('td') ticker = row_data[0].text.strip() price = get_live_price(ticker) # split ticker for checking if same stock of different stock exchange is selected or not stock_name = "" stock_ex = "US" stock_name = ticker #ticker.split(".") if price >= PENNY_STOCK_THRESHOLD and stock_name not in stocks_temp: stocks_temp[stock_name] = stock_ex count += 1 # get back ticker for stock in stocks_temp: stocks.append(f"{stock}") # stocks.append(f"{stock}.{stocks_temp[stock]}") # return deque of stocks to focus on return stocks
# setup for coloured output init() ############################################################## HEADING = ''' __ __ ____ ___ ____/ /___ ______/ /_/ __ \\__ __ / _ \\/ __ / __ `/ ___/ __/ /_/ / / / / / __/ /_/ / /_/ / / / /_/ ____/ /_/ / \\___/\\__,_/\\__,_/_/ \\__/_/ \\__, / /____/ ''' Notify.heading(HEADING) ############################################################## # set time zone global TZ TZ = pytz.timezone('Europe/London') # set holidays HOLIDAYS = holidays.UnitedStates() # set market open time OPEN_TIME = datetime.time(hour=9, minute=15, second=0) # set market close time CLOSE_TIME = datetime.time(hour=15, minute=30, second=0) CHECK_MARKET = False ##############################################################