Ejemplo n.º 1
0
class Application(tk.Frame):

    def __init__(self, master=None, bg=config.background_color):
        super().__init__(master)
        self.master = master
        self.master.configure(background="#1E1E1E")
        self.pack()
        self.create_widgets()
        self.limit_check()

    def create_fonts(self):
        self.font = tkFont.Font(family=config.font, weight=config.font_weight, size=config.font_size)
        self.font_large = tkFont.Font(family=config.font, weight=config.font_weight, size=round(config.font_size * 1.5))
        self.font_small = tkFont.Font(family=config.font, weight=config.font_weight, size=round(config.font_size * .66))

    def create_variables(self):
        # Set up StringVars that will be used.
        self.ticker_value = StringVar()
        self.account_value_text = StringVar()
        self.account_value_text.set(str(account_value))
        self.last_price_value = StringVar()
        self.current_position_value = StringVar()
        self.current_position_pnl = StringVar()
        self.account_value_pnl = StringVar()
        self.limit_price = StringVar()
        self.order_type = StringVar(None, 'market')

    # Create tkinter widgets.
    def create_widgets(self):
        self.create_fonts()
        self.create_variables()

        # Global is_playing as it is used as a boolean and StringVar
        global is_playing
        is_playing = StringVar()
        is_playing.set("▶")

        # Create Ticker Label for Ticker
        self.ticker_id = tk.Label(
            self,
            textvariable=self.ticker_value,
            fg=config.color_white,
            bg=config.background_color,
            font=self.font_large
        ).grid(row=0, column=0, columnspan=4, padx=33, sticky="nsew")

        # Create a label to show the last price
        self.last_price_label = tk.Label(
            self,
            textvariable=self.last_price_value,
            bg=config.background_color,
            fg=config.color_white,
            font=self.font_large
        ).grid(row=1, column=0, columnspan=4, sticky="nsew")

        # Create a button to start the reply
        self.play_button = tk.Button(
            self,
            textvariable=is_playing,
            bg=config.button_color_light,
            fg=config.color_grey,
            borderwidth=0
        )

        self.play_button["command"] = self.play_replay
        self.play_button.grid(row=2, column=0, columnspan=2, sticky="nsew")

        # Create a button for progressing to next bar
        self.next_button = tk.Button(self, text="▮▶", bg=config.button_color_light, fg=config.color_grey, borderwidth=0)
        self.next_button["command"] = self.next_bar
        self.next_button.grid(row=2, column=2, columnspan=2, sticky="nsew")

        # Create a button for long orders
        self.long_button = tk.Button(
            self,
            text="BUY",
            font=self.font,
            bg=config.button_color,
            fg=config.color_green,
            borderwidth=0
        )
        self.long_button["command"] = self.order_buy
        self.long_button.grid(row=3, column=0, columnspan=2, sticky="nsew")

        # Create a button for short orders
        self.short_button = tk.Button(
            self,
            text="SELL",
            font=self.font,
            bg=config.button_color,
            fg=config.color_red,
            borderwidth=0
        )
        self.short_button["command"] = self.order_sell
        self.short_button.grid(row=3, column=2, columnspan=2, sticky="nsew")

        # Create radio buttons to toggle between limit orders and market orders
        self.limit_radiobutton = tk.Radiobutton(
            self,
            bg=config.background_color,
            fg=config.color_dark_grey,
            selectcolor=config.background_color,
            text="LIMIT",
            variable=self.order_type,
            value="limit"
        )
        self.limit_radiobutton.grid(row=4, column=0, columnspan=2, sticky="nsew")

        self.market_radiobutton = tk.Radiobutton(
            self,
            bg=config.background_color,
            fg=config.color_dark_grey,
            selectcolor=config.background_color,
            text="MARKET",
            variable=self.order_type,
            value="market",
        ).grid(row=4, column=2, columnspan=2, sticky="nsew")

        # Create entry box for limit orders
        self.limit_price = tk.Entry(
            self,
            borderwidth=0,
            bg=config.button_color_light,
            fg=config.color_grey)
        self.limit_price.insert(0, " ")
        self.limit_price.grid(row=5, column=0, columnspan=3, sticky="nsew", padx=5)

        self.limit_copy_button = tk.Button(
            self,
            text="LAST",
            borderwidth=0,
            bg=config.button_color,
            fg=config.color_grey,
            font=self.font_small
        )
        self.limit_copy_button["command"] = self.copy_last
        self.limit_copy_button.grid(row=5, column=3, columnspan=1, sticky="nsew")

        self.current_position_label = tk.Label(
            self,
            text="Current Position",
            anchor="w",
            bg=config.background_color,
            fg=config.color_grey, font=self.font_small
        ).grid(row=6, column=0, columnspan=4, sticky="nsew")

        self.current_position_value_label = tk.Label(
            self,
            textvariable=self.current_position_value,
            anchor="w",
            bg=config.button_color_light,
            fg=config.color_dark_grey
        ).grid(row=7, column=0, columnspan=3, sticky="nsew")

        self.current_position_pnl_label = tk.Label(
            self,
            textvariable=self.current_position_pnl,
            anchor="e",
            bg=config.button_color_light,
            fg=config.color_dark_grey
        ).grid(row=7, column=3, columnspan=1, sticky="nsew")

        self.account_value_label = tk.Label(
            self,
            text="Account value",
            anchor="w",
            bg=config.background_color,
            fg=config.color_grey,
            font=self.font_small
        ).grid(row=8, column=0, columnspan=4, sticky="nsew")

        self.account_value_value_label = tk.Label(
            self,
            textvariable=self.account_value_text,
            bg=config.button_color_light,
            fg=config.color_white,
            anchor="w"
        ).grid(row=9, column=0, columnspan=3, sticky="nsew")

        self.account_value_pnl_label = tk.Label(
            self,
            textvariable=self.account_value_pnl,
            bg=config.button_color_light,
            fg=config.color_dark_grey,
            anchor="e"
        ).grid(row=9, column=3, columnspan=1, sticky="nsew")

        self.trade_history_label = tk.Label(
            self,
            text="Trades",
            anchor="w",
            bg=config.background_color,
            fg=config.color_grey,
            font=self.font_small
        ).grid(row=10, column=0, columnspan=3, sticky="nsew")

        self.trade_history_clear = tk.Button(
            self,
            text="Clear",
            bg=config.button_color,
            fg=config.color_grey,
            font=self.font_small,
            borderwidth=0
        )
        self.trade_history_clear.grid(row=10, column=3, columnspan=1, sticky="nsew")
        self.trade_history_clear['command'] = self.clear_list

        self.trade_history_list = tk.Listbox(
            self,
            fg=config.color_grey,
            bg=config.textarea_color,
            borderwidth=0)
        self.trade_history_list.grid(row=11, column=0, columnspan=4, sticky="nsew")

    # Write Timestamp to csv file
    write([time.strftime("%Y-%m-%d %H:%M")])

    # Start of Functions
    def message_box(self):
        messagebox.showinfo('Error', 'Sorry! Limit orders are not currently implemented.\n'
                                     'You can check progress here:\n'
                                     'https://github.com/Robswc/tradingview-trainer/issues/5')
        self.order_type.set('market')

    # Generic function to show error
    def show_error(self, cause, exception, message):
        messagebox.showerror(str(cause), str(str(exception) + '\n' + message))
        driver.get("https://github.com/Robswc/tradingview-trainer/wiki/Errors")

    def clear_list(self):
        clear_csv()
        self.update_labels()

    def get_ticker(self):
        #ticker = driver.find_element_by_xpath(
        #    '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/span[2]/div/div[1]/div'
        #).text
        ticker = driver.find_element_by_xpath(
            '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/span[2]/div/div[1]'
        ).text
        ticker = str(ticker).split(' ')

        print(ticker[0])
        return str(ticker[0])

    def get_price_data(self, request):
        try:
            if request == 'o':
                return float(driver.find_element_by_xpath(
                    '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/div/span[1]/span[2]'
                ).text)

            if request == 'h':
                return float(driver.find_element_by_xpath(
                    '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/div/span[2]/span[2]'
                ).text)

            if request == 'l':
                return float(driver.find_element_by_xpath(
                    '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/div/span[3]/span[2]'
                ).text)

            if request == 'c':
                return float(driver.find_element_by_xpath(
                    '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/div/span[4]/span[2]'
                ).text)
        except:
            return 0

    def get_limit_price(self):
        self.limit_price.get()

    def get_position_pnl(self):
        if get_position()['quantity'] < 0:
            pnl_percent = ((get_position()['entry'] - self.get_last_price()) / get_position()['entry']) * 100
        if get_position()['quantity'] > 0:
            pnl_percent = ((self.get_last_price() - get_position()['entry']) / self.get_last_price()) * 100

        try:
            return round(pnl_percent, 2)
        except:
            return 0

    # Doesn't seem to work :(
    def add_marker(self):
        pass
        # actions = ActionChains(driver)
        # element = driver.find_element_by_xpath('/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]')
        # element.click()
        # actions.click(element).key_down(Keys.ALT, 'v').perform()

    def update_labels(self):

        # update all labels via tk StringVar()
        self.last_price_value.set(str(self.get_last_price()))
        self.current_position_pnl.set(str(self.get_position_pnl()) + '%')
        self.account_value_pnl.set(str(round(percent_change(get_account_value(), float(config.initial_amount)), 2)) + '%')
        self.current_position_value.set(str(get_position()['quantity']) + " @ " + str(get_position()['entry']))
        self.account_value_text.set(locale.currency(get_account_value(), grouping=True))
        self.ticker_value.set(self.get_ticker())

        # Update trade history box
        self.trade_history_list.delete(0, 'end')
        for trade in read_all():
            self.trade_history_list.insert(0, trade)

    # get last price via xpath
    def get_last_price(self):
        try:
            last_price = driver.find_element_by_xpath(
                '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/div/span[4]/span[2]'
            ).text
            return float(last_price)
        except:
            try:
                last_price = driver.find_element_by_xpath(config.custom_xpath_last_price).text
                return float(last_price)
            except Exception as error:
                self.show_error('last_value', str(error), 'Please report error here: ')


    # function to pass buy order to order engine.
    def order_buy(self):
        oe = OrderEngine
        if self.order_type.get() == 'market':
            oe.market(OrderEngine, round(get_account_value(), 2), self.get_last_price())
        if self.order_type.get() == 'limit':
            print('LIMIT BIMIT ORDER HEHEH')
            oe.limit(OrderEngine, round(get_account_value(), 2), float(self.limit_price.get()), self.get_last_price())
        self.update_labels()

    # function to pass sell order to order engine.
    def order_sell(self):
        oe = OrderEngine
        if self.order_type.get() == 'market':
            print(type(get_account_value()), type(self.get_last_price()))
            oe.market(OrderEngine, round(get_account_value(), 2) * -1, float(self.get_last_price()))
        if self.order_type.get() == 'limit':
            oe.limit(OrderEngine, get_account_value() * -1, float(self.limit_price.get()), self.get_last_price())
        self.update_labels()

    # Check with the order engine to see if there is a limit order.
    def limit_check(self):
        oe = OrderEngine
        oe.on_tick(OrderEngine,
                   self.get_price_data('o'),
                   self.get_price_data('h'),
                   self.get_price_data('l'),
                   self.get_price_data('c')
                   )
        global is_playing
        print(str(is_playing.get()))

        if str(is_playing.get()) == "▮▮":
            print(str(is_playing.get()))
            self.after(500, self.limit_check)

    # Function to auto-fill last price into limit price.
    def copy_last(self):
        self.limit_price.delete(0, "end")
        self.limit_price.insert(0, self.last_price_value.get())

    # Click next bar w/selenium, use functions to grab values.
    def next_bar(self):
        print(self.limit_price.get())
        global is_playing
        try:
            driver.find_element_by_xpath('/html/body/div[7]/div/div[2]/div[3]/div').click()
        except:
            try:
                driver.find_element_by_xpath(config.custom_xpath_replay).click()
            except:
                self.show_error('next_bar', 'xpath error', 'Please report error here: ')

        is_playing.set("▶")
        self.limit_check()
        self.update_labels()
        print('>>')

    # Function to click the play-replay with selenium, check for limit orders.
    def play_replay(self):
        global is_playing
        self.update_labels()
        try:
            driver.find_element_by_xpath('/html/body/div[9]/div/div[2]/div[2]/div').click()
        except Exception:
            driver.find_element_by_xpath(config.custom_xpath_play_replay).click()
        print(str(is_playing.get()))
        if str(is_playing.get()) == "▶":
            is_playing.set("▮▮")
            print(str(is_playing))
            self.limit_check()
        else:
            is_playing.set("▶")
            print(str(is_playing))
Ejemplo n.º 2
0
class retailPage(Frame):
    ''' the main page that actually branches into 2 seperate frames for buying and selling
        this frame provides the use with the
'''
    def __init__(self, parent, main, **kw):
        Frame.__init__(self, parent, **kw)
        self.main = main
        self.Head = Label(font=MED_FONT)

        self.retail_back_b = Button(text='BACK', command=self.back_fb)
        self.stock_name = StringVar()
        self.stock_name_ = ''
        self.stock_name_c = Combobox(textvariable=self.stock_name)
        self.stock_name_l = Label(text='Stock name: ')
        self.amount = Entry()
        self.amount_l = Label(text='Number of stocks :')

        self.check_avail_b = Button(text='Check')
        self.cost_l = Label(text='Cost: ')
        self.cost = Label()
        self.buy_stock_b = Button(text='BUY Stock')
        self.sellp_l = Label(text='Current Selling Price: ')
        self.profit_l = Label(text='PROFIT/LOSS')
        self.sell_stock_b = Button(text='SELL Stock')
        self.page = None

    def showItems(self, main):
        self.Head.grid(column=0, row=0, columnspan=2)
        self.Head.configure(text='logged in as %s' % main.present_user)
        if self.page == 'b':
            self.buy()
        elif self.page == 's':
            self.sell()

    def hideItems(self, main):
        self.Head.grid_forget()

    def buy(self):
        '''This function creates the buy window
'''
        self.retail_back_b.grid(column=1, row=5)
        self.retail_back_b.config(command=self.back_fb)
        self.stock_name_l.grid(column=0, row=1)
        self.stock_name_c.grid(column=1, row=1)
        self.stock_name_c.config(values=self.main.shares_dict.keys())
        self.amount_l.grid(column=0, row=2)
        self.amount.grid(column=1, row=2)
        self.check_avail_b.config(command=self.check_avail_buy)
        self.check_avail_b.grid(column=0, row=3)
        self.cost_l.grid(column=0, row=4, columnspan=2)
        self.buy_stock_b.config(command=self.buy_stock,
                                text='Buy Stock',
                                state='disabled')
        self.buy_stock_b.grid(column=0, row=5)

    def sell(self):
        '''This function creats the sell window'''
        self.retail_back_b.grid(column=1, row=6)
        self.retail_back_b.config(command=self.back_fs)
        self.check_avail_b.config(command=self.check_avail_sell)
        self.stock_name_l.grid(column=0, row=1)
        self.stock_name_c.grid(column=1, row=1)
        self.stock_name_c.config(values=self.main.shares_dict.keys())
        self.amount_l.grid(column=0, row=2)
        self.amount.grid(column=1, row=2)
        self.check_avail_b.grid(column=0, row=3)
        self.sellp_l.grid(column=0, row=4, columnspan=2)
        self.profit_l.grid(column=0, row=5, columnspan=2)
        self.sell_stock_b.config(command=self.sell_stock,
                                 state='disabled',
                                 text='Check')
        self.sell_stock_b.grid(column=0, row=6)

    def back_fb(self):
        '''Back from buy i.e. removes all the items needed to make buy'''
        self.retail_back_b.grid_forget()
        self.Head.grid(column=0, row=0, columnspan=2)
        self.stock_name_l.grid_forget()
        self.stock_name_c.grid_forget()
        self.amount_l.grid_forget()
        self.amount.grid_forget()
        self.check_avail_b.grid_forget()
        self.cost_l.grid_forget()
        self.buy_stock_b.grid_forget()
        self.buy_stock_b.config(state='disabled')

        self.main.show_frame(VIEW_STOCK, RETAIL_PAGE)
        self.stock_name.set('')
        self.amount.delete(0, END)

    def back_fs(self):
        ''' Back from sell i.e. removes all the items needed to make it sell window'''
        self.Head.grid(column=0, row=0, columnspan=2)
        self.retail_back_b.grid_forget()
        self.check_avail_b.grid_forget()
        self.stock_name_l.grid_forget()
        self.stock_name_c.grid_forget()
        self.amount_l.grid_forget()
        self.amount.grid_forget()
        self.sellp_l.grid_forget()
        self.profit_l.grid_forget()
        self.sell_stock_b.grid_forget()

        self.main.show_frame(VIEW_STOCK, RETAIL_PAGE)
        self.stock_name.set('')
        self.amount.delete(0, END)
        self.check_avail_b.grid_forget()

    def check_avail_buy(self):
        ''' Performs a check whether the number of shares requisted are available or not and then check whether the
            person has the required amounts of fund or not for the transaction to go through'''
        name = self.stock_name.get()
        l2 = self.main.accounts[self.main.present_user]

        if name in self.main.shares_dict.keys():
            li = self.main.shares_dict[name]
        else:
            self.stock_name.delete(0, END)
            showinfo(meassage='Enter a Valid Stock name')

        available_num = int(li['tot_amount']) - int(li['tot_sold'])
        req = int(self.amount.get())
        cost = req * int(li['cost'])

        if req < 0:
            showinfo(message='Enter a Valid amount')
        elif req > available_num:
            showinfo(message='Enter an amount less than ' + str(available_num))
        elif cost > int(l2['balance']):
            showinfo(message='You have only %s in you account' % l2['balance'])
        else:
            self.cost_l.config(text='Cost: \t' + li['cost'] + '*' + str(req) +
                               '=' + str(cost))
            self.buy_stock_b.config(state='normal')

    def check_avail_sell(self):
        ''' Performs a check whether the user has enough stocks to sell'''
        name = self.stock_name.get()
        if name in self.main.shares_dict.keys():
            li = self.main.shares_dict[name]
        else:
            self.stock_name.delete(0, END)
            showinfo(message='Enter a Valid Stock name')
        req = int(self.amount.get())
        if req < 0:
            showinfo(message='Please Enter a Valid amount')
            self.amount.delete(0, END)
        li = self.main.p_user_dict
        ok = False
        for i in li:
            if name == i['name']:
                ok = True
                buff = i

        if req > int(buff['tot_owned']):
            showinfo(message='You dont have that many stocks try less than ' +
                     buff['tot_owned'])
            self.amount.delete(0, END)
        cost = self.main.shares_dict[name]['cost']
        tot_cost = req * int(cost)
        try:
            spent = req * float(buff['money_spent']) / int(buff['tot_owned'])
        except:
            spent = 0
        pol = tot_cost - spent

        if pol >= 0:
            self.profit_l.config()
        elif pol < 0:
            self.profit_l.config()
        if req <= int(buff['tot_owned']):
            self.sellp_l.config(text='Current Selling Price: \t' + cost)
            self.profit_l.config(text="PROFIT-LOSS: \t" + str(pol))
            self.sell_stock_b.config(command=self.sell_stock,
                                     text='Sell Stock')
            showinfo(message=
                     'Everthing is ok, \nClicking Sell will execute the trade')
            self.sell_stock_b.config(state='normal')

    def buy_stock(self):
        '''Finally Executes the transaction and asks the user for conformation one last time'''
        name = self.stock_name.get()
        li = self.main.shares_dict[name]

        for i in range(len(self.main.p_user_dict)):
            if name == self.main.p_user_dict[i]['name']:
                index = i
        req = int(self.amount.get())
        tot_cost = req * int(li['cost'])
        self.main.shares_dict[name]['tot_sold'] = str(
            int(self.main.shares_dict[name]['tot_sold']) + req)
        self.main.p_user_dict[index]['tot_owned'] = str(
            int(self.main.p_user_dict[index]['tot_owned']) + req)
        self.main.p_user_dict[index]['money_spent'] = str(
            int(self.main.p_user_dict[index]['money_spent']) + tot_cost)
        self.main.users_dict[
            self.main.present_user][index] = self.main.p_user_dict[index]
        balance = int(self.main.accounts[self.main.present_user]['balance'])
        self.main.accounts[self.main.present_user]['balance'] = str(balance -
                                                                    tot_cost)
        self.cost_l.config(text='Cost: ')

        showinfo(
            message='You have just bought %s of the stock %s at the price %s' %
            (str(req), name, str(tot_cost)))
        self.stock_name.set('')
        self.main.show_frame(VIEW_STOCK, RETAIL_PAGE)
        self.back_fb()

    def sell_stock(self):
        '''Asks the user for conformation and then completes the transaction
        of selling, at this point the profit field is
        also updated'''
        name = self.stock_name.get()
        req = int(self.amount.get())

        li = self.main.p_user_dict
        for i in range(len(li)):
            if name == li[i]['name']:
                ok = True
                buff = i

        tot_cost = req * int(self.main.shares_dict[name]['cost'])
        try:
            spent = req * float(
                self.main.p_user_dict[buff]['money_spent']) / int(
                    self.main.p_user_dict[buff]['tot_owned'])
        except ZeroDivisionError:
            spent = 0
        self.main.shares_dict[name]['tot_sold'] = str(
            int(self.main.shares_dict[name]['tot_sold']) - req)
        self.main.p_user_dict[buff]['tot_owned'] = str(
            int(self.main.p_user_dict[buff]['tot_owned']) - req)
        pol = tot_cost - spent
        diff = int(self.main.p_user_dict[buff]['money_spent']) - tot_cost
        self.main.p_user_dict[buff]['money_spent'] = str(
            diff) if diff > 0 else '0'
        self.main.users_dict[self.main.present_user] = self.main.p_user_dict
        profit = int(self.main.accounts[self.main.present_user]['profit'])
        self.main.accounts[self.main.present_user]['profit'] = str(
            int(profit + pol))
        balance = int(self.main.accounts[self.main.present_user]['balance'])
        self.main.accounts[self.main.present_user]['balance'] = str(balance +
                                                                    tot_cost)
        self.retail_back_b.grid_forget()
        self.profit_l.config(text='PROFIT/LOSS: ')
        self.sellp_l.config(text='Current selling price: ')
        self.main.show_frame(VIEW_STOCK, RETAIL_PAGE)
        self.back_fs()
Ejemplo n.º 3
0
    txt_history = Text(
        frm_R,
        font=font,
        state='normal',
        width=31,
        height=15
    )
    scrollb = Scrollbar(frm_R)
    scrollb.config(command=txt_history.yview)
    txt_history.config(yscrollcommand=scrollb.set)
    scrollb.grid(row=1, column=1, pady=pady, sticky='nsew')
    txt_history.grid(row=1, column=0, pady=pady, sticky='nsew')

    btn_clear_history = Button(
        frm_R,
        text='Clear history',
        command=lambda: txt_history.delete('1.0', END)
    )
    btn_clear_history.grid(
        row=2,
        column=0,
        columnspan=2,
        padx=padx,
        pady=pady,
        sticky='nsew'
    )
    # END: Content of the frm_R frame.

    root.mainloop()