tradezero_api.watchlist

  1from __future__ import annotations
  2
  3import time
  4import warnings
  5
  6import pandas as pd
  7from selenium.webdriver.common.by import By
  8from selenium.webdriver.common.keys import Keys
  9
 10
 11class Watchlist:
 12    """
 13    this class is for managing the data withing the watchlist container
 14    note that if the container is placed on the left side of the UI it will show
 15    only about half of the properties (Last, Bid, Ask, %Chg, Chg, Vol) instead of all 12.
 16    """
 17    def __init__(self, driver):
 18        self.driver = driver
 19        self.symbols = set()
 20
 21    def add(self, symbol: str):
 22        """
 23        add symbol to watchlist
 24
 25        :param symbol:
 26        :raises Exception: if given symbol is not valid
 27        """
 28        symbol = symbol.upper()
 29        symbol_input = self.driver.find_element(By.ID, 'trading-l1-input-symbol')
 30        symbol_input.send_keys(symbol, Keys.RETURN)
 31
 32        time.sleep(0.4)
 33        if self._symbol_valid(symbol):
 34            self.symbols.add(symbol)
 35        else:
 36            raise Exception(f'Error: Given symbol is not valid ({symbol})')
 37
 38    def remove(self, symbol: str):
 39        """
 40        remove symbol from watchlist
 41
 42        :param symbol:
 43        """
 44        symbol = symbol.upper()
 45        if symbol not in self._get_current_symbols():
 46            warnings.warn(f'Given Symbol is not present in watchlist ({symbol})')
 47            return
 48
 49        delete_button = f'//*[@id="wl-{symbol}"]/td[1]'
 50        self.driver.find_element(By.XPATH, delete_button).click()
 51        self.symbols.remove(symbol)
 52
 53    def reset(self):
 54        """
 55        remove all symbols from watchlist
 56        """
 57        rows = self.driver.find_elements(By.XPATH, '//*[@id="trading-l1-tbody"]/tr/td[1]')
 58        for delete_button in rows:
 59            delete_button.click()
 60        self.symbols = set()
 61
 62    def restore(self):
 63        """
 64        make sure all symbols that have been added,
 65        are present in the watchlist (after refresh the watchlist resets)
 66        """
 67        current_list = set(self._get_current_symbols())  # set because the order might be different
 68        if self.symbols != current_list:
 69            for symbol in self.symbols:
 70                if symbol not in current_list:
 71                    self.add(symbol)
 72
 73    def _get_current_symbols(self):
 74        """
 75        return list with current symbols on watchlist
 76        """
 77        rows = self.driver.find_elements(By.XPATH, '//*[@id="trading-l1-tbody"]/tr/td[2]')
 78        if len(rows) == 0:
 79            return []
 80
 81        data = self.data('dict')
 82        return list(data.keys())
 83
 84    def _symbol_valid(self, symbol: str):
 85        """
 86        check if a symbol is valid
 87
 88        :param symbol:
 89        :return: bool
 90        """
 91        last_notif_message = self.driver.find_element(By.CSS_SELECTOR, 'span.message').text
 92        if last_notif_message == f'Symbol not found: {symbol.upper()}':
 93            return False
 94        return True
 95
 96    def data(self, return_type: str = 'df'):
 97        """
 98        returns the watchlist table as either a DataFrame or Dict,
 99        if return_type is equal to: 'df' it will return a pandas.DataFrame
100        or if return_type equal to: 'dict' it will return a Dictionary with the symbols as keys
101        and the data as values.
102        note that if there are no symbols in the watchlist, Pandas will not be able
103        to locate the table and therefore will return False
104
105        :param return_type: 'df' or 'dict'
106        :return: None if empty, else: DF or dict
107        """
108        symbols_lst = self.driver.find_elements(By.XPATH, '//*[@id="trading-l1-tbody"]//td[2]')
109        if len(symbols_lst) == 0:
110            warnings.warn('There are no symbols present in your watchlist')
111            return None
112
113        # selenium can only read visible rows, while pandas can find also non-visible text
114        # if there are no rows pandas will not be able to locate the table, and throw an error
115        df = pd.read_html(self.driver.page_source, attrs={'id': 'trading-l1-table'})[0]
116
117        if len(df.columns) == 8:
118            df = df.drop(columns=[0])  # drop 'x'
119            df.columns = ['symbol', 'last', 'bid', 'ask', '%chg', 'chg', 'vol']
120
121        elif len(df.columns) == 14:
122            df = df.drop(columns=[0, 2])  # drop 'x' and currency_get_current_symbols
123            df.columns = ['symbol', 'open', 'close', 'last', 'bid', 'ask',
124                          'high', 'low', '%chg', 'chg', 'vol', 'time']
125
126        df = df.set_index('symbol')
127        if return_type == 'dict':
128            return df.to_dict('index')
129        return df
class Watchlist:
 12class Watchlist:
 13    """
 14    this class is for managing the data withing the watchlist container
 15    note that if the container is placed on the left side of the UI it will show
 16    only about half of the properties (Last, Bid, Ask, %Chg, Chg, Vol) instead of all 12.
 17    """
 18    def __init__(self, driver):
 19        self.driver = driver
 20        self.symbols = set()
 21
 22    def add(self, symbol: str):
 23        """
 24        add symbol to watchlist
 25
 26        :param symbol:
 27        :raises Exception: if given symbol is not valid
 28        """
 29        symbol = symbol.upper()
 30        symbol_input = self.driver.find_element(By.ID, 'trading-l1-input-symbol')
 31        symbol_input.send_keys(symbol, Keys.RETURN)
 32
 33        time.sleep(0.4)
 34        if self._symbol_valid(symbol):
 35            self.symbols.add(symbol)
 36        else:
 37            raise Exception(f'Error: Given symbol is not valid ({symbol})')
 38
 39    def remove(self, symbol: str):
 40        """
 41        remove symbol from watchlist
 42
 43        :param symbol:
 44        """
 45        symbol = symbol.upper()
 46        if symbol not in self._get_current_symbols():
 47            warnings.warn(f'Given Symbol is not present in watchlist ({symbol})')
 48            return
 49
 50        delete_button = f'//*[@id="wl-{symbol}"]/td[1]'
 51        self.driver.find_element(By.XPATH, delete_button).click()
 52        self.symbols.remove(symbol)
 53
 54    def reset(self):
 55        """
 56        remove all symbols from watchlist
 57        """
 58        rows = self.driver.find_elements(By.XPATH, '//*[@id="trading-l1-tbody"]/tr/td[1]')
 59        for delete_button in rows:
 60            delete_button.click()
 61        self.symbols = set()
 62
 63    def restore(self):
 64        """
 65        make sure all symbols that have been added,
 66        are present in the watchlist (after refresh the watchlist resets)
 67        """
 68        current_list = set(self._get_current_symbols())  # set because the order might be different
 69        if self.symbols != current_list:
 70            for symbol in self.symbols:
 71                if symbol not in current_list:
 72                    self.add(symbol)
 73
 74    def _get_current_symbols(self):
 75        """
 76        return list with current symbols on watchlist
 77        """
 78        rows = self.driver.find_elements(By.XPATH, '//*[@id="trading-l1-tbody"]/tr/td[2]')
 79        if len(rows) == 0:
 80            return []
 81
 82        data = self.data('dict')
 83        return list(data.keys())
 84
 85    def _symbol_valid(self, symbol: str):
 86        """
 87        check if a symbol is valid
 88
 89        :param symbol:
 90        :return: bool
 91        """
 92        last_notif_message = self.driver.find_element(By.CSS_SELECTOR, 'span.message').text
 93        if last_notif_message == f'Symbol not found: {symbol.upper()}':
 94            return False
 95        return True
 96
 97    def data(self, return_type: str = 'df'):
 98        """
 99        returns the watchlist table as either a DataFrame or Dict,
100        if return_type is equal to: 'df' it will return a pandas.DataFrame
101        or if return_type equal to: 'dict' it will return a Dictionary with the symbols as keys
102        and the data as values.
103        note that if there are no symbols in the watchlist, Pandas will not be able
104        to locate the table and therefore will return False
105
106        :param return_type: 'df' or 'dict'
107        :return: None if empty, else: DF or dict
108        """
109        symbols_lst = self.driver.find_elements(By.XPATH, '//*[@id="trading-l1-tbody"]//td[2]')
110        if len(symbols_lst) == 0:
111            warnings.warn('There are no symbols present in your watchlist')
112            return None
113
114        # selenium can only read visible rows, while pandas can find also non-visible text
115        # if there are no rows pandas will not be able to locate the table, and throw an error
116        df = pd.read_html(self.driver.page_source, attrs={'id': 'trading-l1-table'})[0]
117
118        if len(df.columns) == 8:
119            df = df.drop(columns=[0])  # drop 'x'
120            df.columns = ['symbol', 'last', 'bid', 'ask', '%chg', 'chg', 'vol']
121
122        elif len(df.columns) == 14:
123            df = df.drop(columns=[0, 2])  # drop 'x' and currency_get_current_symbols
124            df.columns = ['symbol', 'open', 'close', 'last', 'bid', 'ask',
125                          'high', 'low', '%chg', 'chg', 'vol', 'time']
126
127        df = df.set_index('symbol')
128        if return_type == 'dict':
129            return df.to_dict('index')
130        return df

this class is for managing the data withing the watchlist container note that if the container is placed on the left side of the UI it will show only about half of the properties (Last, Bid, Ask, %Chg, Chg, Vol) instead of all 12.

Watchlist(driver)
18    def __init__(self, driver):
19        self.driver = driver
20        self.symbols = set()
driver
symbols
def add(self, symbol: str):
22    def add(self, symbol: str):
23        """
24        add symbol to watchlist
25
26        :param symbol:
27        :raises Exception: if given symbol is not valid
28        """
29        symbol = symbol.upper()
30        symbol_input = self.driver.find_element(By.ID, 'trading-l1-input-symbol')
31        symbol_input.send_keys(symbol, Keys.RETURN)
32
33        time.sleep(0.4)
34        if self._symbol_valid(symbol):
35            self.symbols.add(symbol)
36        else:
37            raise Exception(f'Error: Given symbol is not valid ({symbol})')

add symbol to watchlist

Parameters
  • symbol:
Raises
  • Exception: if given symbol is not valid
def remove(self, symbol: str):
39    def remove(self, symbol: str):
40        """
41        remove symbol from watchlist
42
43        :param symbol:
44        """
45        symbol = symbol.upper()
46        if symbol not in self._get_current_symbols():
47            warnings.warn(f'Given Symbol is not present in watchlist ({symbol})')
48            return
49
50        delete_button = f'//*[@id="wl-{symbol}"]/td[1]'
51        self.driver.find_element(By.XPATH, delete_button).click()
52        self.symbols.remove(symbol)

remove symbol from watchlist

Parameters
  • symbol:
def reset(self):
54    def reset(self):
55        """
56        remove all symbols from watchlist
57        """
58        rows = self.driver.find_elements(By.XPATH, '//*[@id="trading-l1-tbody"]/tr/td[1]')
59        for delete_button in rows:
60            delete_button.click()
61        self.symbols = set()

remove all symbols from watchlist

def restore(self):
63    def restore(self):
64        """
65        make sure all symbols that have been added,
66        are present in the watchlist (after refresh the watchlist resets)
67        """
68        current_list = set(self._get_current_symbols())  # set because the order might be different
69        if self.symbols != current_list:
70            for symbol in self.symbols:
71                if symbol not in current_list:
72                    self.add(symbol)

make sure all symbols that have been added, are present in the watchlist (after refresh the watchlist resets)

def data(self, return_type: str = 'df'):
 97    def data(self, return_type: str = 'df'):
 98        """
 99        returns the watchlist table as either a DataFrame or Dict,
100        if return_type is equal to: 'df' it will return a pandas.DataFrame
101        or if return_type equal to: 'dict' it will return a Dictionary with the symbols as keys
102        and the data as values.
103        note that if there are no symbols in the watchlist, Pandas will not be able
104        to locate the table and therefore will return False
105
106        :param return_type: 'df' or 'dict'
107        :return: None if empty, else: DF or dict
108        """
109        symbols_lst = self.driver.find_elements(By.XPATH, '//*[@id="trading-l1-tbody"]//td[2]')
110        if len(symbols_lst) == 0:
111            warnings.warn('There are no symbols present in your watchlist')
112            return None
113
114        # selenium can only read visible rows, while pandas can find also non-visible text
115        # if there are no rows pandas will not be able to locate the table, and throw an error
116        df = pd.read_html(self.driver.page_source, attrs={'id': 'trading-l1-table'})[0]
117
118        if len(df.columns) == 8:
119            df = df.drop(columns=[0])  # drop 'x'
120            df.columns = ['symbol', 'last', 'bid', 'ask', '%chg', 'chg', 'vol']
121
122        elif len(df.columns) == 14:
123            df = df.drop(columns=[0, 2])  # drop 'x' and currency_get_current_symbols
124            df.columns = ['symbol', 'open', 'close', 'last', 'bid', 'ask',
125                          'high', 'low', '%chg', 'chg', 'vol', 'time']
126
127        df = df.set_index('symbol')
128        if return_type == 'dict':
129            return df.to_dict('index')
130        return df

returns the watchlist table as either a DataFrame or Dict, if return_type is equal to: 'df' it will return a pandas.DataFrame or if return_type equal to: 'dict' it will return a Dictionary with the symbols as keys and the data as values. note that if there are no symbols in the watchlist, Pandas will not be able to locate the table and therefore will return False

Parameters
  • return_type: 'df' or 'dict'
Returns

None if empty, else: DF or dict