def execute(self, quantity, price):
        global position

        # Check if position is increasing or decreasing.
        # If position is decreasing, take the difference and use it to get PNLs for the trade.
        if abs(position['quantity'] + quantity) < abs(position['quantity']):
            self.calculate_pnl(quantity, position['entry'], price)
            self.calculate_pnl_percent(quantity, position['entry'], price)
            add_realized_pnl(
                self.calculate_pnl(quantity, position['entry'], price))
            write([
                quantity, '@', price,
                round(
                    self.calculate_pnl_percent(quantity, position['entry'],
                                               price), 2), '%'
            ])
            print()

        # If increasing position average them for entry price
        if abs(position['quantity'] + quantity) > abs(position['quantity']):
            write([quantity, '@', price])
            print('increasing')
            if position['entry'] != 0:
                print('average')
                position['entry'] = statistics.mean([position['entry'], price])
            else:
                position['entry'] = price

        # Set Position
        position['quantity'] = position['quantity'] + quantity
        print('Position: ' + str(position['quantity']))
        if position['quantity'] == 0:
            position['entry'] = 0
Example #2
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))