Skip to content

Commit

Permalink
Adapt to T212 new App, fix candle stick
Browse files Browse the repository at this point in the history
  • Loading branch information
HellAmbro committed Apr 3, 2024
1 parent 219baa4 commit 9d34fb8
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 98 deletions.
3 changes: 3 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### v0.2.7
* fix candle stick
* adapt api with new T212 app
### v0.2.6
* removed depreacted driver manager
* fix cfd/equity switch
Expand Down
3 changes: 3 additions & 0 deletions config.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[ACCOUNT]
email[email protected]
password=your_password
127 changes: 81 additions & 46 deletions examples/Instrument_pricing_history_example.ipynb

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,26 @@

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

from pytrading212 import Equity, Company
from pytrading212 import Mode, EquityOrder, OrderType
from pytrading212 import Mode
from pytrading212.constants import ONE_WEEK


config = configparser.ConfigParser()
config.read('../config.ini')


if __name__ == '__main__':
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver = webdriver.Chrome(service=Service())
equity = Equity(
email=config['ACCOUNT']['email'], password=config['ACCOUNT']['password'],
driver=driver, mode=Mode.DEMO
)

# Create a new instrument
instrument = Company(instrument_code="AAPLL_US_EQ", isin="")
instrument = Company(instrument_code="AAPL_US_EQ", isin="")

# Request pricing history for the instrument, this requires a time interval
# and a trading 212 instance
print(
instrument.get_pricing_history(interval=ONE_WEEK, trading_instance=equity)
instrument.get_pricing_history(interval=ONE_WEEK, headers=equity.headers, trading_instance=equity)
)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pytrading212"
version = "0.2.5"
version = "0.2.7"
description = "Unofficial Trading212 API"
authors = ["HellAmbro <[email protected]>"]
license = "MIT License"
Expand Down
50 changes: 48 additions & 2 deletions pytrading212/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,54 @@
CLASS_LOGIN_BUTTON = "SubmitButton_input__IV2dl"
CLASS_EQUITY_ICON = "equity-icon"
CLASS_CFD_ICON = "cfd-icon"
PYTRADING212_VERSION = "0.2.5"
PYTRADING212_VERSION = "0.2.6"
SELECTOR_NEW_APP = ("#root > div > div > div > div > div > div > div:nth-child(1) > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-105ug2t > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-105ug2t > div > div > div > div "
"> div > div > div > div.css-175oi2r.r-13awgt0 > div > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-12vffkv > div:nth-child(2) > div "
"> div.css-175oi2r.r-13awgt0.r-1udh08x > div > div.css-175oi2r.r-13awgt0 > div > div > div > div "
"> div > div > div.css-175oi2r.r-13awgt0 > div > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-12vffkv > div:nth-child(2) > div "
"> div.css-175oi2r.r-13awgt0.r-1udh08x > div > div.css-175oi2r.r-13awgt0 > div > div > "
"div.css-175oi2r.r-150rngu.r-eqz5dr.r-16y2uox.r-1wbh5a2.r-11yh6sk.r-1rnoaur.r-1sncvnh > div > "
"div.css-175oi2r.r-1loqt21.r-1otgn73 > div > div")
SELECTOR_MENU_BUTTON = ("#root > div > div > div > div > div > div > div:nth-child(1) > div > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-12vffkv > div > div > "
"div:nth-child(1) > div > div > div:nth-child(2) > div > div:nth-child(5) > div > span > div")
SELECTOR_LIVE_ACCOUNT = ("#root > div > div > div > div > div > div > div:nth-child(1) > div > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-12vffkv > div > div > "
"div:nth-child(1) > div > div > div:nth-child(3) > div:nth-child(1) > div > div > div")
SELECTOR_LIVE_EQUITY = ("#root > div > div > div > div > div > div > div:nth-child(1) > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-105ug2t > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-105ug2t > div:nth-child(3) > "
"div > div.css-175oi2r.r-12vffkv > div > div > "
"div.css-175oi2r.r-150rngu.r-eqz5dr.r-16y2uox.r-11yh6sk.r-1rnoaur.r-1sncvnh > div > "
"div:nth-child(2) > div:nth-child(1) > div:nth-child(1) > div.css-175oi2r")
SELECTOR_DEMO_EQUITY = ("#root > div > div > div > div > div > div > div:nth-child(1) > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-105ug2t > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-105ug2t > div:nth-child(3) > "
"div > div.css-175oi2r.r-12vffkv > div > div > "
"div.css-175oi2r.r-150rngu.r-eqz5dr.r-16y2uox.r-11yh6sk.r-1rnoaur.r-1sncvnh > div > "
"div:nth-child(2) > div:nth-child(1) > div:nth-child(1)")
SELECTOR_MENU_LIST = ("#root > div > div > div > div > div > div > div:nth-child(1) > div > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-12vffkv > div > div > "
"div:nth-child(2) > div > div > div:nth-child(2) > div > div > div > div > div > "
"div.css-175oi2r.r-13awgt0 > div > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-12vffkv > div:nth-child(2) > "
"div > div > div > div.css-175oi2r.r-13awgt0 > div > div:nth-child(1)")
SELECTOR_SWITCH_DEMO = ("#root > div > div > div > div > div > div > div:nth-child(1) > div > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-12vffkv > div > div > "
"div:nth-child(2) > div > div > div:nth-child(2) > div > div > div > div > div > "
"div.css-175oi2r.r-13awgt0 > div > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-12vffkv > div:nth-child(2) > "
"div > div > div > div.css-175oi2r.r-13awgt0 > div > div:nth-child(1) > div > div > div > div "
"> div.css-175oi2r.r-13awgt0 > div > "
"div.css-175oi2r.r-1p0dtai.r-1d2f490.r-u8s1d.r-zchlnj.r-ipm5af.r-12vffkv > div:nth-child(2) > "
"div > div.css-175oi2r.r-13awgt0.r-1udh08x > div > div.css-175oi2r.r-13awgt0 > div > "
"div:nth-child(2) > div.css-175oi2r.r-150rngu.r-eqz5dr.r-16y2uox.r-1wbh5a2.r-11yh6sk.r"
"-1rnoaur.r-1sncvnh > div > div:nth-child(3) > "
"div.css-175oi2r.r-1otgn73.r-1loqt21.r-1awozwy.r-1777fci.r-utggzx")

ONE_WEEK = "ONE_WEEK"

Expand All @@ -32,7 +79,6 @@ class Period(Enum):
ALL = "ALL",



class OrderType(Enum):
"""Order Type"""
LIMIT = "LIMIT"
Expand Down
22 changes: 9 additions & 13 deletions pytrading212/instrument.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import datetime
import typing
import requests
import json
import typing

from constants import ONE_WEEK

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options
import requests


class CandleStick(object):

"""
The candlestick object is a representaion of the values used in a candlestick
chart.
Expand All @@ -32,9 +25,12 @@ class CandleStick(object):
timestamp: datetime.datetime
unknown: int

def __init__(self, data: typing.List) -> None:
def __init__(self, data: typing.List) -> None:
self.timestamp, self.high, self.low, self.opening, self.closing, self.unknown = data

def __repr__(self) -> str:
return (f"CandleStick(timestamp={self.timestamp}, high={self.high}, low={self.low},"
f" opening={self.opening}, closing={self.closing}, unknown={self.unknown})")


class Company:
Expand All @@ -50,9 +46,9 @@ def __init__(self, instrument_code: str, isin: str, language_code: str = 'en'):
def get_pricing_history(
self,
interval: str,
headers: dict,
trading_instance: 'Trading212'
) -> typing.List[CandleStick]:

ticker_data: str = json.dumps(
{
"candles":
Expand All @@ -61,15 +57,15 @@ def get_pricing_history(
"ticker": self.instrument_code,
"useAskPrice": True,
"period": interval,
"size":500
"size": 500
}
]
}
)

response = requests.put(
f"{trading_instance.base_url}{self.charting_url}?ticker={self.instrument_code}&languageCode={self.language_code}",
headers=equity.headers,
headers=headers,
data=ticker_data
)
return [
Expand Down
50 changes: 22 additions & 28 deletions pytrading212/trading212.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,18 @@ def __init__(
# Click login button
self.driver.find_element(By.CLASS_NAME, constants.CLASS_LOGIN_BUTTON).click()

# Wait until the site is fully loaded, 120 seconds is a lot, but the site sometimes is very slow
WebDriverWait(self.driver, 120).until(expected_conditions.
visibility_of_element_located((By.CLASS_NAME, "company-logo")))
# Close new app button, should be removed later
try:
WebDriverWait(self.driver, 30).until(expected_conditions.visibility_of_element_located(
(By.CSS_SELECTOR, constants.SELECTOR_NEW_APP)))
self.driver.find_element(By.CSS_SELECTOR, constants.SELECTOR_NEW_APP).click()
except NoSuchElementException:
pass

self.user_agent = self.driver.execute_script("return navigator.userAgent;")

# Redirect to correct mode, DEMO or LIVE
if mode.name not in self.driver.current_url:
self.driver.get(self.base_url)
WebDriverWait(self.driver, 120).until(expected_conditions.
visibility_of_element_located((By.CLASS_NAME, "company-logo")))

# Switch to right trading session: CFD or EQUITY
self.switch_to(trading=trading)

# Switch to get also DEMO token
self.switch()
# Get session cookie
cookies = self.driver.get_cookies()
if cookies is not None:
Expand Down Expand Up @@ -103,22 +100,19 @@ def finish(self):
console.log("Closing session.")
self.driver.close()

def switch_to(self, trading: constants.Trading):
if not self.driver.find_elements(By.ID, "platform-loader"):
self.driver.find_element(By.CLASS_NAME, "account-menu-info").click()
WebDriverWait(self.driver, 10).until(expected_conditions.
visibility_of_element_located((By.CLASS_NAME, "account-types")))
element_account_types = self.driver.find_element(By.CLASS_NAME, "account-types")
if trading == constants.Trading.CFD:
element_account_types.find_element(By.CLASS_NAME, "cfd").click()
WebDriverWait(self.driver, 60).until(expected_conditions.
visibility_of_element_located((By.CLASS_NAME, "cfd-icon")))
elif trading == constants.Trading.EQUITY:
element_account_types.find_element(By.CLASS_NAME, "equity").click()
WebDriverWait(self.driver, 60).until(expected_conditions.
visibility_of_element_located((By.CLASS_NAME, "equity-icon")))
else:
self.switch_to(trading)
def switch(self):
WebDriverWait(self.driver, 30).until(expected_conditions.visibility_of_element_located(
(By.CSS_SELECTOR, constants.SELECTOR_MENU_BUTTON)))
self.driver.find_element(By.CSS_SELECTOR, constants.SELECTOR_MENU_BUTTON).click()

self.driver.execute_script("arguments[0].scroll(0, arguments[0].scrollHeight);",
self.driver.find_element(By.CSS_SELECTOR, constants.SELECTOR_MENU_LIST))
self.driver.find_element(By.CSS_SELECTOR, constants.SELECTOR_SWITCH_DEMO).click()
WebDriverWait(self.driver, 30).until(expected_conditions.visibility_of_element_located(
(By.CSS_SELECTOR, constants.SELECTOR_DEMO_EQUITY)))
self.driver.find_element(By.CSS_SELECTOR, constants.SELECTOR_DEMO_EQUITY).click()
# Wait some seconds to initialize cookies
time.sleep(5)

def get_funds(self):
"""Get your funds, free, available."""
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="pytrading212",
version="0.2.6",
version="0.2.7",
author="HellAmbro",
author_email="[email protected]",
description="Unofficial Trading212 API",
Expand Down

0 comments on commit 9d34fb8

Please sign in to comment.