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))
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()
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()