Skip to content

Commit 2e2a047

Browse files
committed
0.1.1
1 parent fde7cdf commit 2e2a047

File tree

8 files changed

+414
-16
lines changed

8 files changed

+414
-16
lines changed

MANIFEST

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
setup.cfg
33
setup.py
44
viaduct\__init__.py
5+
viaduct\cfd.py
56
viaduct\core.py
7+
viaduct\equity.py
68
viaduct\installer.py
79
viaduct\installerUtils.py
810
viaduct\isa.py

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pip install viaduct
2525

2626
## Import and Usage
2727

28-
Viaduct is an API wrapper. API responses are returned python dictionaries, see the root tree images for more information. Selenium web scrapping modes extend the public class so it does not need to be recreated.
28+
Viaduct is an API wrapper. API responses are returned python dictionaries, see the root tree images for more information. Selenium web scrapping modes extend the public class methods so it does not need to be recreated.
2929

3030
Examples are the payloads that the Rest API returns, these are returned as Python dictionaries for your convenience
3131

@@ -64,7 +64,7 @@ Selenium powered wrapper for management of an ISA account, real mode only
6464
If Firefox is not installed in default folder, make sure you pass the installed path upon initialisation:
6565

6666
```python
67-
instance = ISA("email", "password", browserPath=r"C:\Program Files\Mozilla Firefox\firefox.exe")
67+
instance = ISA("email", "password", browserPath=r"C:\Program Files\Mozilla Firefox\firefox.exe", loadSymbols=False)
6868
```
6969

7070
## Equity Mode
@@ -74,7 +74,7 @@ Selenium powered wrapper for management of an Equity account, real or demo modes
7474
If Firefox is not installed in default folder, make sure you pass the installed path upon initialisation:
7575

7676
```python
77-
instance = Equity("email", "password", reality=Reality.Real, browserPath=r"C:\Program Files\Mozilla Firefox\firefox.exe")
77+
instance = Equity("email", "password", reality=Reality.Real, browserPath=r"C:\Program Files\Mozilla Firefox\firefox.exe", loadSymbols=False)
7878
```
7979

8080
## CFD Mode
@@ -86,7 +86,7 @@ Custom methods for CFD are not yet supported and only return Public API calls
8686
If Firefox is not installed in default folder, make sure you pass the installed path upon initialisation:
8787

8888
```python
89-
instance = CFD("email", "password", reality=Reality.Real, browserPath=r"C:\Program Files\Mozilla Firefox\firefox.exe")
89+
instance = CFD("email", "password", reality=Reality.Real, browserPath=r"C:\Program Files\Mozilla Firefox\firefox.exe", loadSymbols=False)
9090
```
9191

9292
## API Class Methods

dist/viaduct-0.0.12.tar.gz

-7.83 KB
Binary file not shown.

lib/equityISAShared.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Format url on whether is live
2+
def urlf(self, url):
3+
if (self.reality == Reality.Real):
4+
return ("https://live.trading212.com" + url)
5+
elif (self.reality == Reality.Practice):
6+
return ("https://demo.trading212.com" + url)
7+
else:
8+
raise Exception("Invalid reality " + self.reality)
9+
10+
# Gets min and max buy and sell value in £, max sell quantity is number of shares
11+
# Not sure what sellThreshold is
12+
# The sell parameters only appear for UK stocks for some reason
13+
def getMinMax(self, code):
14+
return get(self.urlf("/rest/v1/equity/value-order/min-max?instrumentCode=" + code), cookies=self.cookiePayload)
15+
16+
# Takes instrument code, returns maxBuy and maxSell in shares for the account and max buy and sell that is technically
17+
# possible on the exchange, also has minTrade and if suspended
18+
def getSettings(self, code):
19+
return post(self.urlf("/rest/v2/account/instruments/settings"), cookies=self.cookiePayload, payload=[code])
20+
21+
# Gets the account performance graph data
22+
def getPortfolioPerformance(self, historyPeriod):
23+
return get(self.urlf("/rest/v2/portfolio?period=" + historyPeriod), cookies=self.cookiePayload)
24+
25+
# Get all instruments on Trading212!
26+
def getAllInstruments(self):
27+
return get(self.urlf("/rest/v2/instruments/"))
28+
29+
# Gets company ISINs and tickers for graphs etc
30+
def getTickers(self):
31+
return get(self.urlf("/rest/companies"))
32+
33+
# Saves all instruments in a dictionary useful for symbol lookup
34+
def saveAllInstruments(self):
35+
logging.info("Loading all instruments, this will take a while...")
36+
self.instruments = self.getAllInstruments()
37+
# Don't think getting tickers is actually required
38+
#self.tickerISINs = self.getTickers()
39+
self.loadedInstruments = True
40+
41+
# Search the instrument dictionary
42+
def instrumentSearch(self, searchUsing, searchKey, resultUsing):
43+
if (not self.loadedInstruments):
44+
self.saveAllInstruments()
45+
for i in self.instruments:
46+
try:
47+
if (i[searchUsing] == searchKey):
48+
return i[resultUsing]
49+
except:
50+
pass
51+
52+
# Gets a symbols name
53+
def getName(self, isin="", prettyName="", code="", id=""):
54+
if (isin != ""):
55+
return self.instrumentSearch("isin", isin, "name")
56+
if (prettyName != ""):
57+
return self.instrumentSearch("prettyName", prettyName, "name")
58+
if (code != ""):
59+
return self.instrumentSearch("code", code, "name")
60+
if (id != ""):
61+
return self.instrumentSearch("id", id, "name")
62+
else:
63+
raise Exception(
64+
"ISIN, prettyName, code, or id is required to find name")
65+
66+
# Gets a symbols prettyName
67+
def getPrettyName(self, isin="", name="", code="", id=""):
68+
if (isin != ""):
69+
return self.instrumentSearch("isin", isin, "prettyName")
70+
if (name != ""):
71+
return self.instrumentSearch("name", name, "prettyName")
72+
if (code != ""):
73+
return self.instrumentSearch("code", code, "prettyName")
74+
if (id != ""):
75+
return self.instrumentSearch("id", id, "prettyName")
76+
else:
77+
raise Exception(
78+
"ISIN, name, code, or id is required to find prettyName")
79+
80+
# Gets a symbols code
81+
def getCode(self, isin="", name="", prettyName="", id=""):
82+
if (isin != ""):
83+
return self.instrumentSearch("isin", isin, "code")
84+
if (name != ""):
85+
return self.instrumentSearch("name", name, "code")
86+
if (prettyName != ""):
87+
return self.instrumentSearch("prettyName", prettyName, "code")
88+
if (id != ""):
89+
return self.instrumentSearch("id", id, "code")
90+
else:
91+
raise Exception(
92+
"ISIN, name, prettyName, or id is required to find code")
93+
94+
# Gets a symbols ISIN
95+
def getISIN(self, name="", prettyName="", code="", id=""):
96+
if (name != ""):
97+
return self.instrumentSearch("name", name, "isin")
98+
if (prettyName != ""):
99+
return self.instrumentSearch("prettyName", prettyName, "isin")
100+
if (code != ""):
101+
return self.instrumentSearch("code", code, "isin")
102+
if (id != ""):
103+
return self.instrumentSearch("id", id, "isin")
104+
else:
105+
raise Exception(
106+
"Name, prettyName, code, or id is required to find ISIN")
107+
108+
# Gets a symbols ID
109+
def getID(self, isin="", name="", prettyName="", code=""):
110+
if (isin != ""):
111+
return self.instrumentSearch("isin", isin, "id")
112+
if (name != ""):
113+
return self.instrumentSearch("name", name, "id")
114+
if (prettyName != ""):
115+
return self.instrumentSearch("prettyName", prettyName, "id")
116+
if (code != ""):
117+
return self.instrumentSearch("code", code, "id")
118+
else:
119+
raise Exception(
120+
"ISIN, name, prettyName, or code is required to find id")
121+
122+
# Get instrument details position code from the secret API
123+
def getInstrument(self, code):
124+
return get(self.urlf("/rest/v2/instruments/" + code))
125+
126+
# Get instrument details by ISIN
127+
# If language is not available, Trading212 seems to return English
128+
def getFundamentals(self, isin, langCode="en"):
129+
return get(self.urlf("/rest/companies/fundamentals?languageCode=" + langCode + "&isin=" + isin))
130+
131+
# Gets chart data for a particular ticker
132+
# When getting chart data, the ticker returned is the code not what is on the stock exchange!
133+
def getChartData(self, code, chartPeriod, size, includeFake=False):
134+
payload = {
135+
"candles": [
136+
{
137+
"ticker": code,
138+
"period": chartPeriod,
139+
"size": size,
140+
"includeFake": includeFake
141+
}
142+
]
143+
}
144+
return post(url=self.urlf("/charting/v2/batch"), payload=payload)

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
setup(
44
name='viaduct', # How you named your package folder (MyLib)
55
packages=['viaduct'], # Chose the same as "name"
6-
version='0.1.0', # Start with a small number and increase it with every change you make
6+
version='0.1.1', # Start with a small number and increase it with every change you make
77
# Chose a license from here: https://help.github.com/articles/licensing-a-repository
88
license='gpl-3.0',
99
# Give a short description about your library
@@ -14,7 +14,7 @@
1414
# Provide either the link to your github or to your website
1515
url='https://github.com/harrytwigg/Viaduct-Trading212-Python-API',
1616
# I explain this later on
17-
download_url='https://github.com/harrytwigg/Viaduct-Trading212-Python-API/archive/0.1.0.tar.gz',
17+
download_url='https://github.com/harrytwigg/Viaduct-Trading212-Python-API/archive/0.1.1.tar.gz',
1818
keywords=['python', 'api', 'rest', 'api-wrapper', 'viaduct', 'trading212',
1919
'trading212-api'], # Keywords that define your package best
2020
install_requires=[ # I get to this in a second

viaduct/cfd.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
class CFD(CoreModule):
6-
def __init__(self, email, password, reality, browserPath, headless=False, timeout=2):
6+
def __init__(self, email, password, reality, browserPath, headless=False, timeout=2, loadSymbols=False):
77
super().__init__(email, password, TradingType.CFD,
88
reality, headless, browserPath, timeout)
99
self.reality = reality

viaduct/equity.py

Lines changed: 131 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33

44

55
class Equity(CoreModule):
6-
def __init__(self, email, password, reality, browserPath, headless=False, timeout=2):
6+
def __init__(self, email, password, reality, browserPath, headless=False, timeout=2, loadSymbols=False):
77
super().__init__(email, password, TradingType.Equity,
88
reality, headless, browserPath, timeout)
9-
self.reality = reality
9+
self.reality = Reality.Real
10+
11+
if (loadSymbols):
12+
self.saveAllInstruments()
13+
else:
14+
self.loadedInstruments = False
1015

1116
# Format url on whether is live
1217
def urlf(self, url):
@@ -21,13 +26,134 @@ def urlf(self, url):
2126
# Not sure what sellThreshold is
2227
# The sell parameters only appear for UK stocks for some reason
2328
def getMinMax(self, code):
24-
return super().get(self.urlf("/rest/v1/equity/value-order/min-max?instrumentCode=" + code), cookies=self.cookiePayload)
29+
return get(self.urlf("/rest/v1/equity/value-order/min-max?instrumentCode=" + code), cookies=self.cookiePayload)
2530

2631
# Takes instrument code, returns maxBuy and maxSell in shares for the account and max buy and sell that is technically
2732
# possible on the exchange, also has minTrade and if suspended
2833
def getSettings(self, code):
29-
return super().post(self.urlf("/rest/v2/account/instruments/settings"), cookies=self.cookiePayload, payload=[code])
34+
return post(self.urlf("/rest/v2/account/instruments/settings"), cookies=self.cookiePayload, payload=[code])
3035

3136
# Gets the account performance graph data
3237
def getPortfolioPerformance(self, historyPeriod):
33-
return super().get(self.urlf("/rest/v2/portfolio?period=" + historyPeriod), cookies=self.cookiePayload)
38+
return get(self.urlf("/rest/v2/portfolio?period=" + historyPeriod), cookies=self.cookiePayload)
39+
40+
# Get all instruments on Trading212!
41+
def getAllInstruments(self):
42+
return get(self.urlf("/rest/v2/instruments/"))
43+
44+
# Gets company ISINs and tickers for graphs etc
45+
def getTickers(self):
46+
return get(self.urlf("/rest/companies"))
47+
48+
# Saves all instruments in a dictionary useful for symbol lookup
49+
def saveAllInstruments(self):
50+
logging.info("Loading all instruments, this will take a while...")
51+
self.instruments = self.getAllInstruments()
52+
# Don't think getting tickers is actually required
53+
#self.tickerISINs = self.getTickers()
54+
self.loadedInstruments = True
55+
56+
# Search the instrument dictionary
57+
def instrumentSearch(self, searchUsing, searchKey, resultUsing):
58+
if (not self.loadedInstruments):
59+
self.saveAllInstruments()
60+
for i in self.instruments:
61+
try:
62+
if (i[searchUsing] == searchKey):
63+
return i[resultUsing]
64+
except:
65+
pass
66+
67+
# Gets a symbols name
68+
def getName(self, isin="", prettyName="", code="", id=""):
69+
if (isin != ""):
70+
return self.instrumentSearch("isin", isin, "name")
71+
if (prettyName != ""):
72+
return self.instrumentSearch("prettyName", prettyName, "name")
73+
if (code != ""):
74+
return self.instrumentSearch("code", code, "name")
75+
if (id != ""):
76+
return self.instrumentSearch("id", id, "name")
77+
else:
78+
raise Exception(
79+
"ISIN, prettyName, code, or id is required to find name")
80+
81+
# Gets a symbols prettyName
82+
def getPrettyName(self, isin="", name="", code="", id=""):
83+
if (isin != ""):
84+
return self.instrumentSearch("isin", isin, "prettyName")
85+
if (name != ""):
86+
return self.instrumentSearch("name", name, "prettyName")
87+
if (code != ""):
88+
return self.instrumentSearch("code", code, "prettyName")
89+
if (id != ""):
90+
return self.instrumentSearch("id", id, "prettyName")
91+
else:
92+
raise Exception(
93+
"ISIN, name, code, or id is required to find prettyName")
94+
95+
# Gets a symbols code
96+
def getCode(self, isin="", name="", prettyName="", id=""):
97+
if (isin != ""):
98+
return self.instrumentSearch("isin", isin, "code")
99+
if (name != ""):
100+
return self.instrumentSearch("name", name, "code")
101+
if (prettyName != ""):
102+
return self.instrumentSearch("prettyName", prettyName, "code")
103+
if (id != ""):
104+
return self.instrumentSearch("id", id, "code")
105+
else:
106+
raise Exception(
107+
"ISIN, name, prettyName, or id is required to find code")
108+
109+
# Gets a symbols ISIN
110+
def getISIN(self, name="", prettyName="", code="", id=""):
111+
if (name != ""):
112+
return self.instrumentSearch("name", name, "isin")
113+
if (prettyName != ""):
114+
return self.instrumentSearch("prettyName", prettyName, "isin")
115+
if (code != ""):
116+
return self.instrumentSearch("code", code, "isin")
117+
if (id != ""):
118+
return self.instrumentSearch("id", id, "isin")
119+
else:
120+
raise Exception(
121+
"Name, prettyName, code, or id is required to find ISIN")
122+
123+
# Gets a symbols ID
124+
def getID(self, isin="", name="", prettyName="", code=""):
125+
if (isin != ""):
126+
return self.instrumentSearch("isin", isin, "id")
127+
if (name != ""):
128+
return self.instrumentSearch("name", name, "id")
129+
if (prettyName != ""):
130+
return self.instrumentSearch("prettyName", prettyName, "id")
131+
if (code != ""):
132+
return self.instrumentSearch("code", code, "id")
133+
else:
134+
raise Exception(
135+
"ISIN, name, prettyName, or code is required to find id")
136+
137+
# Get instrument details position code from the secret API
138+
def getInstrument(self, code):
139+
return get(self.urlf("/rest/v2/instruments/" + code))
140+
141+
# Get instrument details by ISIN
142+
# If language is not available, Trading212 seems to return English
143+
def getFundamentals(self, isin, langCode="en"):
144+
return get(self.urlf("/rest/companies/fundamentals?languageCode=" + langCode + "&isin=" + isin))
145+
146+
# Gets chart data for a particular ticker
147+
# When getting chart data, the ticker returned is the code not what is on the stock exchange!
148+
def getChartData(self, code, chartPeriod, size, includeFake=False):
149+
payload = {
150+
"candles": [
151+
{
152+
"ticker": code,
153+
"period": chartPeriod,
154+
"size": size,
155+
"includeFake": includeFake
156+
}
157+
]
158+
}
159+
return post(url=self.urlf("/charting/v2/batch"), payload=payload)

0 commit comments

Comments
 (0)