예제 #1
0
 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("")
예제 #2
0
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
예제 #3
0
    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)
예제 #4
0
    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)
예제 #5
0
 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()
예제 #6
0
 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()
예제 #7
0
    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("")
예제 #8
0
 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"])}')
예제 #9
0
    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 !")
예제 #10
0
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)
예제 #11
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
예제 #12
0
# 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
##############################################################