Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
This is a Pyhton based API using selenium and requests to get information from the trading212 Platform, please note that either myself or trading212 take responsibility for the outcomes related to the uses of this API.
I will continue to work on this project and would appriciate any feedback.
pip install apit212
to start using this API you will first need to login to the account using apit212 you will then be able to use all the functions and create your own trading bot or use it to scarpe data from the trading212 platform.
from apit212 import *
api = Apit212()
api.setup(username="flock92@account.api", password="pass******", mode="demo")
from apit212 import *
api = Apit212()
api.setup(username="flock92@account.api", password="pass******", mode="live")
It's good practice to set up an env file to save sensitive informaton like your user name or password. Here is a useful link .env
USER=flock92@account.api
PASS=password123
from dotenv import load_dotenv
from apit212 import *
import os
load_dotenv('.env')
username: str = os.getenv('USER')
password: str = os.getenv('PASS')
api = Apit212()
api.setup(username="flock92@account.api", password="pass******", mode="demo")
This API is useless without the correct ticker symbol so i've got a solution.
from apit212 import Tickers
ticker = Tickers()
print(ticker.fetch_symbols(symbol='META'))
print(ticker.find_by_name(full_name='tesla'))
There is quite a bit of data to read through but the key you are after is ticker this will return the symbol used by the trading212 platform.
[{'ticker': 'FB', 'type': 'STOCK', 'currency': 'USD', 'shortName': 'META', 'fullName': 'Meta Platforms', 'description': 'Meta Platforms Inc', 'minTrade': 0.1, 'digitsPrecision': 2, 'exchangeId': 68, 'tradable': True, 'underlyingInstrumentTicker': 'FB_US_EQ', 'underlyingLeverageCoefficient': 1.0, 'dealerExclusions': [], 'maxOpenLong': 1121, 'leverage': '1:5', 'insignificantDigits': 0, 'baseTicker': nan, 'expiryDate': nan, 'minTradeSizeCoefficient': 10.0, 'isin': 'US30303M1027', 'countryOfOrigin': 'US', 'quantityPrecision': 1.0, 'priorityIndex': 25.0, 'maxTrade': nan, 'conditionalVisibility': nan, 'suspended': nan}]
[{'ticker': 'TSLA', 'type': 'STOCK', 'currency': 'USD', 'shortName': 'TSLA', 'fullName': 'Tesla', 'description': 'Tesla, Inc.', 'minTrade': 0.1, 'digitsPrecision': 2, 'exchangeId': 68, 'tradable': True, 'underlyingInstrumentTicker': 'TSLA_US_EQ', 'underlyingLeverageCoefficient': 1.0, 'dealerExclusions': [], 'maxOpenLong': 1405, 'leverage': '1:5', 'insignificantDigits': 0, 'baseTicker': nan, 'expiryDate': nan, 'minTradeSizeCoefficient': 10.0, 'isin': 'US88160R1014', 'countryOfOrigin': 'US', 'quantityPrecision': 1.0, 'priorityIndex': 100.0, 'maxTrade': nan, 'conditionalVisibility': nan, 'suspended': nan}]
from apit212 import Tickers
ticker = Tickers()
meta = ticker.fetch_symbols(symbol='META')
print(len(meta))
print(meta[0]['ticker'])
finding a ticker using the widely used ticker will often return 1 result but on some occasions you may get multiple results so its good practice to check the len of the string returned.
1
FB
To trade CFD's simply call the CFD class
from apit212 import *
api = Apit212()
api.setup(username="flock92@account.api", password="pass******", mode="demo")
cfd = CFD(cred=api)
To trade Equity's simply call the Equity class.
from apit212 import *
client = Apit212(username="flock92@account.api", password="pass******", mode="live")
equity = Equity()
The auth_validate function will return account ID and trade type.
validate = cfd.auth_validate()
print(validate)
{'id': '*******-****-****-****-************', 'accountId': ********, 'customerId': *********, 'tradingType': 'CFD', 'customerUuid': '********-****-****-****-************', 'frontend': 'WC4', 'readyToTrade': True, 'deviceUuid': ''}
The get_account function will return your account details.
account = cfd.get_account()
print(account)
{'demoAccounts': [{'id': ********, 'type': 'DEMO', 'tradingType': 'CFD', 'customerId': ********,
'createdDate': '2023-01-17T03:20:48.000+00:00', 'status': 'ACTIVE', 'registerSource': 'WC4',
'currencyCode': 'GBP', 'readyToTrade': True}], 'liveAccounts': [{'id': ********, 'type': 'LIVE',
'tradingType': 'CFD', 'customerId': ********, 'createdDate': '2023-01-17T03:20:32.000+00:00',
'status': 'PENDING_ACTIVATION', 'registerSource': 'WC4', 'currencyCode': 'GBP', 'readyToTrade': False}]}
The get_funds function will return the accounts funds.
funds = cfd.get_funds()
print(funds)
{'*******': {'accountId': ********, 'tradingType': 'CFD', 'currency': 'GBP',
'freeForWithdraw': 486.83, 'freeForCfdTransfer': 0, 'total': 486.83,
'lockedCash': {'totalLockedCash': 0, 'lockedCash': []}}}
The get_summary returns a summary of you account.
summary = cfd.get_summary()
print(summary)
'open': {'unfilteredCount': 1, 'items': [{'positionId': '********-****-****-****-************', 'humanId': '********',
'created': '2023-07-03T18:17:46.563+03:00', 'averagePrice': 192.25, 'averagePriceConverted': 150.73025341182984,
'currentPrice': 192.2, 'value': 1054.82, 'investment': 1055.11, 'code': 'AAPL', 'margin': 212.02, 'ppl': -0.28,
'quantity': 7, 'maxBuy': 9.0, 'maxSell': 7, 'maxOpenBuy': 2033.0, 'maxOpenSell': 2040.0, 'swap': -1.06, 'frontend': 'WC4'}]}
The get_companies returns instruments avaliable to trade on the trading212 platform
companies = cfd.get_companies()
print(companies)
[{'ticker': 'SIGTl_EQ', 'isin': 'GB0008769993'}, {'ticker': 'PDYPY_US_EQ', 'isin': 'US3440441026'}...]
The get_instruments_info will return information about an instrument.
info = cfd.get_instruments_info(instrument="TSLA")
print(info)
{'code': 'TSLA', 'type': 'STOCK', 'margin': 0.2, 'shortPositionSwap': -0.07030593058663,
'longPositionSwap': -0.27928156941337, 'tsSwapCharges': '1970-01-01T23:00:00.000+02:00',
'marginPercent': '20', 'leverage': '1:5'}
The get_order_info get
orderInfo = cfd.get_order_info(instrument="TSLA", quamtity=1.5)
print(orderInfo)
{'buyMargin': 40.18, 'sellMargin': 40.18, 'buySwap': -0.2, 'sellSwap': -0.05}
tickers = ["TSLA","AAPL"]
deviation = cfd.get_deviations(instruments=tickers)
print(deviation)
[{'request': {'ticker': 'TSLA', 'useAskPrice': False}, 'response': {'timestamp': 1694073610000, 'price': 250.68, 'period': 'd1'}}, {'request': {'ticker': 'AAPL', 'useAskPrice': False}, 'response': {'timestamp': 1694073610000, 'price': 178.18, 'period': 'd1'}}]
The get_position returns infomation for a given position ID, this ID's can be exstracted from the get_summary function
position = cfd.get_position(position_id=274187113)
print(position)
[{'eventType': {'action': 'opened', 'source': 'MARKET_ORDER'},
'eventNumber': {'name': 'MO3053019640', 'id': '274187113', 'frontend': 'WC4'}, 'time': '2023-08-02T22:42:54.000+03:00',
'direction': 'sell', 'quantity': 1.0, 'price': '105.29', 'avgQuantity': 1.0, 'avgPrice': '105.2900', 'modifiedDirection':
'sell'}]
The get_all_result function will return a list of all your trading results. you will need to request each page. you may also need to pass your timezone.
results = cfd.get_all_results()
print(results)
{'data': [{'direction': 'buy', 'code': 'AAPL', 'quantity': 0.1, 'orderNumber': {'name': 'P************', 'link': 'positionHistory/********-****-****-****-************', 'id': '********-****-****-****-************', 'frontend': 'WC4'}, 'price': '176.6700', 'closePrice': '181.98', 'result': '0.42', 'eventNumber': {'name': 'PO3062546222', 'id': '********-****-****-****-************'}, 'eventType': 'closed', 'time': '2023-08-29T17:15:55.000+03:00', 'openingTime': '2023-08-25T11:51:15.000+03:00'}, ...], 'nextPage': 'result?perPage=20&onlyFullyClosed=false&page=2', 'currentPage': 'result?perPage=20&onlyFullyClosed=false&page=1', 'totalSize': 133}
orderHist = cfd.get_order_hist(page_number=1)
print(orderHist)
{'data': [], 'currentPage': 'order?filter=all&perPage=20&from=2023-09-06T02:00:00.000+03:00&to=2023-09-08T01:59:59.173+03:00&page=1', 'totalSize': 0}
positionHist = cfd.get_posistion_hist(page_number=1)
print(positionHist)
{'data': [], 'currentPage': 'position?perPage=20&from=2023-09-06T02:00:00.000+03:00&to=2023-09-08T01:59:59.173+03:00&page=1', 'totalSize': 0}
The fast_price retruns an instruments price as a float. if the request fails None is returned
price = cfd.fast_price(instrument="TSLA")
print(price)
253.49
The chart_data returns a dictionary with the candle date OHLC (open, high, low, close) the period requested. which is set to 1minute by default.
charts = cfd.chart_data(instrument="TSLA", period="ONE_MINUTE")
print(charts)
[{'request': {'ticker': 'TSLA', 'period': 'ONE_MINUTE', 'size': 500, 'useAskPrice': False}, 'response': {'candles': [[1691152740000, 259.6, 259.97, 259.43, 259.49, 47], [1691152800000, 259.38, 259.94, 259.17, 259.56, 58], [1691152860000, 259.62, 260.34, 259.62, 260.19, 42]
The multi_price function will return the last qouted price for all passed instruments.
tickers =["TSLA","AAPL","GOOG"]
multiprice = cfd.multi_price(instruments=tickers)
print(multiprice)
[{'ticker': 'TSLA', 'price': 251.34}, {'ticker': 'AAPL', 'price': 181.96}, {'ticker': 'GOOG', 'price': 135.18}]
The market_order function submits a market order and requires the current price of the instrument.
targetPrice = cfd.fast_price(instrument="TSLA")
marketOrder = cfd.market_order(instrument="TSLA", target_price=targePrice,
quantity=1.5, take_profit=10, stop_loss=10 )
The limit_order function submits a limit order
marketOrder = cfd.limit_order(instrument="TSLA", target_price=127,
quantity=1.5, take_profit=10, stop_loss=10)
The set_limits function allows you to modify or add a stoploss or takeprofit to an existing postion (the positionID is required to carry out this function)
limits = cfd.set_limits(position_id=27361748, TP=10, SL=10)
The add_trailing_stop function adds a trailing stop to an existing position
trailing = cfd.add_trailing_stop(position_id=27361748, distance=1)
The close_position function is used to close an open position. it will required the current price.
currentPrice = cfd.fast_price(instrument="TSLA")
close = cfd.close_position(position_id=23948174, current_price=currentPrice)
cancelAll = cfd.cancel_all_orders()
The cancel_order function is used to cancel a limit order.
cancel = cfd.cancel_order(order_id=**********)
the get_live function will return the current price of a ticker
tickers = ["TSLA", "AAPL"]
prices = cfd.live_price(instruments=tickers)
print(prices)
[{'request': {'ticker': 'TSLA', 'useAskPrice': False}, 'response': {'timestamp': 1690531210000, 'price': 255.8, 'period': 'd1'}}, {'request': {'ticker': 'AAPL', 'useAskPrice': False}, 'response': {'timestamp': 1690531210000, 'price': 193.29, 'period': 'd1'}}]
The get_funds function will return your accounts funds.
funds = cfd.get_funds()
print(funds)
{'20434246': {'accountId': ********, 'tradingType': 'CFD', 'currency': 'GBP',
'freeForWithdraw': 486.83, 'freeForCfdTransfer': 0, 'total': 486.83,
'lockedCash': {'totalLockedCash': 0, 'lockedCash': []}}}
the trailing_stop function allows you to add a trailing stop to a open position.
trailing_stop = cfd.trailing_stop(position_id="***-****-***", distance=0.5)
The add_limits function allows you to add a stoploss and takeprofit to an existing position.
update_limits = client.add_limits(position_id="***-****-***", TP=1 , SL=1)
To set a new stoploss or takeprofit just pass the distance to the TP (take profit) or SL (stop loss) params. The function will get the current price and apply the distance.
The all_position_hist function will return the position history.
position_history = cfd.all_position_hist()
The all_order_hist returns orders data
order_history = cfd.all_order_hist()
The get_instrument function will retunr information about the instrument.
tsla_info = cfd.get_instruments_info(instrument='TSLA')
print(tsla_info)
{'code': 'TSLA', 'type': 'STOCK', 'margin': 0.2, 'shortPositionSwap': -0.07030593058663,
'longPositionSwap': -0.27928156941337, 'tsSwapCharges': '1970-01-01T23:00:00.000+02:00',
'marginPercent': '20', 'leverage': '1:5'}
The get_position function will returns information for the qouted positionID.
position = cfd.get_position(position_id="***-****-***")
print(position)
[{'eventType': {'action': 'opened', 'source': 'MARKET_ORDER'},
'eventNumber': {'name': 'MO3053019640', 'id': '274187113', 'frontend': 'WC4'}, 'time': '2023-08-02T22:42:54.000+03:00',
'direction': 'sell', 'quantity': 1.0, 'price': '105.29', 'avgQuantity': 1.0, 'avgPrice': '105.2900', 'modifiedDirection':
'sell'}]
The get_summary function will return the account summary. this function can also be used to get order ID's and there current PPL
summary = cfd.get_summary()
print(summary)
'open': {'unfilteredCount': 1, 'items': [{'positionId': '********-****-****-****-************', 'humanId': '********',
'created': '2023-07-03T18:17:46.563+03:00', 'averagePrice': 192.25, 'averagePriceConverted': 150.73025341182984,
'currentPrice': 192.2, 'value': 1054.82, 'investment': 1055.11, 'code': 'AAPL', 'margin': 212.02, 'ppl': -0.28,
'quantity': 7, 'maxBuy': 9.0, 'maxSell': 7, 'maxOpenBuy': 2033.0, 'maxOpenSell': 2040.0, 'swap': -1.06, 'frontend': 'WC4'}]}
The live_price function will return the current ask price for the passed instrument.
ticker = ["TSLA","AAPL","GOOG"]
live_price = cfd.live_price(instruments=ticker)
print(live_price)
[{'ticker': 'TSLA', 'price': 253.49}, {'ticker': 'AAPL', 'price': 182.08}, {'ticker': 'GOOG', 'price': 128.44}]
The fast_price function will return the last qouted chart price as a float
price = cfd.fast_price(instrument="TSLA")
print(price)
253.49
the chart_data function will return the lastest chart data for passed instrument
chart = cfd.chart_data(instrument="TSLA")
print(chart)
[{'request': {'ticker': 'TSLA', 'period': 'ONE_MINUTE', 'size': 500, 'useAskPrice': False}, 'response': {'candles': [[1691152740000, 259.6, 259.97, 259.43, 259.49, 47], [1691152800000, 259.38, 259.94, 259.17, 259.56, 58], [1691152860000, 259.62, 260.34, 259.62, 260.19, 42]
The get_deviations function will return price deviations
ticker = ["TSLA","AAPL","GOOG"]
deviations = cfd.get_deviations(instruments=ticker)
print(deviations)
[{'request': {'ticker': 'TSLA', 'useAskPrice': False}, 'response': {'timestamp': 1691136010000, 'price': 259.38, 'period': 'd1'}}, {'request': {'ticker': 'AAPL', 'useAskPrice': False}, 'response': {'timestamp': 1691136010000, 'price': 188.99, 'period': 'd1'}}, {'request': {'ticker': 'GOOG', 'useAskPrice': False}, 'response': {'timestamp': 1691136010000, 'price': 129.05, 'period': 'd1'}}]
The get_companies function will return companies currently listed on T212 & their respective isin ID.
companies = cfd.get_companies()
print(companies)
[{'ticker': 'SIGTl_EQ', 'isin': 'GB0008769993'}, {'ticker': 'PDYPY_US_EQ', 'isin': 'US3440441026'}...]
The limit_order function submit a limit order and takes quantity, target_price, take_profit & stop_loss parms.
limit_order = cfd.limit_order(instrument="TSLA",
quantity=5, target_price=129, take_profit=130, stop_loss=128)
{'account': {'dealer': 'AVUSUK', 'positions': [{'positionId': '********-****-****-****-************',
'humanId': '**********', 'created': '2023-07-03T18:17:46.563+03:00' ...
The market_order function submit a market order and takes quantity, target_price, take_profit & stop_loss parms.
market_order = cfd.market_order(instrument="TSLA",
quantity=5, target_price=129, take_profit=130, stop_loss=128)
The cancel_order function will cancel a pending order it requires a orderID.
cancel_order = cfd.cancel_order(order_id)
You can also use the cancel_all_orders to cancel all pending limits orders.
cancel_all = cfd.cancel_all_orders()
The close_position function will submit a request to cancel a open position.
close_position = cfd.close_position(position_id='ordexxxxx', current_price=current_price)
username = "flock92@account.api"
password = "password132"
api = Apit212()
api.setup(username=username, password=password, mode="demo")
cfd = CFD(cred=api)
target_price = 128
while True:
sleep(60)
price = cfd.fast_price("TSLA")
if price <= target_price:
marketOrder = cfd.market_order(instrument="TSLA", target_price=price, quantity=1, take_profit=10,
stop_loss=10)
break
When carrying out a trade you might run into issues and it's always good to have protocols in place to deal with these issues when they arise.
below is a list of some exceptions you might come across when carrying out a trade.
Just stop making the request if you get this response
This is currently only working with equity accounts and you can only submit trades on your demo account. please read the official documentation to get a better understanding and limitations of the API.
In order to use the official API you will need to generate a key using the trading212 app. /settings/API(Beta) then simply generate a new Key and pass it to the Apitkey().Equity() Class.
from apit212 import *
key = "20557******************************"
client = Apitkey()
info = client.Equity(api_key=key, mode="live")
Here are the functions avalible using the trading212 API-token.
This is an unofficial API & either myself of trading212 are responsible for the use of this API. It is strongly advised that you use a practice account before moving onto real money. apit212 is not a trading bot
FAQs
Unofficial trading212 API
We found that apit212 demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.