For anyone who has previously attempted to use Python to integrate with Forex.com’s API for algorithmic training and failed, I feel for you. Due to “alright” API documentation on Forex.com’s end, and a lack of documentation on the Lightstreamer side of things, it was no easy feat to get something working. With that being said, after going on a short hiatus of not working on this and then revisiting it with fresh eyes, I can finally utilize Forex.com’s API and place trades via Python.
Forex.com is a foreign exchange broker. In layman’s terms, they’re a service that allows you to exchange currency for other currencies (like converting US dollars to Euros) on the foreign exchange market. The foreign exchange market is the largest financial market in the world, with a daily volume of over 6 trillion dollars. For reference, the U.S. stock market sees about 90 billion dollars of daily volume. Due to this high level, there’s a lot of liquidity in the forex market, making it a great candidate for algorithmic trading.
Before anything else, an account with Forex.com is needed, and thankfully they offer demo accounts, so you don’t have to risk your actual money when you’re getting your code setup and working.
As far as I know, the only way to gain API access for the created account is by contacting their support team and requesting API access. This process may have been improved since my experience, but I’m sure this approach will still work even if there’s an automated process now.
This is also the only way I’m aware of to gain access to the API documentation, as I haven’t been able to search for it using a search engine. Due to this, I will not be able to show screenshots or snippets from the documentation itself, but I will show my implementation.
A session ID is needed for every request made to the API, so we need to get one before doing anything else. To do this, we’ll need to make a POST request to the TradingAPI’s session endpoint. The body of the POST will need to include our username, password, and app key. The username and password are the exact same as you would use to access the Forex.com WebTrader, and the app key is a value that gets provided to you when you set up API access to your live or demo account. Here’s an example get_session()
method
def get_session():
body = {
"UserName": {YOUR_USERNAME},
"Password": {YOUR_PASSWORD},
"AppKey": {YOUR_APP_KEY},
"AppVersion": "1",
"AppComments": "",
}
response = requests.post('https://ciapi.cityindex.com/TradingAPI/session', json=body)
if response.status_code == 200:
return response.json()['Session']
else:
return None
Now that we have our session ID, we can now retrieve our Trading Account ID from the API. To do so, we need to make a request to the /useraccount/ClientAndTradingAccount endpoint. This call and all other requests require us to include authentication headers, which consist of your username and the session ID from the step above. Here’s an example get_trading_account_id()
method
def get_trading_account_id():
response = requests.get(
'https://ciapi.cityindex.com/TradingAPI/useraccount/ClientAndTradingAccount',
headers={
"UserName": {YOUR_USERNAME},
"Session": {YOUR_SESSION_ID}
}
if response.status_code == 200:
return response.json()['TradingAccounts'][0]['TradingAccountId']
else:
return None
Now we need to get some market IDs for the different markets we might want to trade in. For this example, I’ll only be looking to place trades in the EUR/USD market. This is probably one of the simplest requests we’ll make. The endpoint we need to hit is the /market/fullsearchwithtags endpoint, which takes in a query parameter that lets us pass in the market names we want information about. Here’s an example get_market_info()
method
def get_market_info():
response = requests.get(
'https://ciapi.cityindex.com/TradingAPI/market/fullsearchwithtags?query=EUR%2FUSD',
headers={
"UserName": {YOUR_USERNAME},
"Session": {YOUR_SESSION_ID}
}
)
if response.status_code == 200:
return response.json()['MarketInformation'][0]['MarketId']
else:
return None
Here’s where the meat and potatoes of this process come in. All previous and future steps involve us making requests to a HTTP service, but we need to interface with a streaming API to get current price data. In this case, Forex.com is using a library called Lightstreamer (https://lightstreamer.com) to stream data to clients. Unfortunately, there is no python client library straight from Lightstreamer. Fortunately, someone has made their own version for us to use. To use it, just run:
pip install lightstreamer-client
Now that we have our Lightstreamer Client library, we need to build the connection and subscribe to the correct data stream. First things first, we need to create a LightstreamerClient object. This takes in our username, session ID, API Url, and something named an adapter_set
. In this instance, the adapter_set
is STREAMINGALL.
lightstreamer_client = LightstreamerClient(
{YOUR_USERNAME},
{YOUR_SESSION_ID},
"https://push.cityindex.com/",
"STREAMINGALL"
)
Next up is creating our LightstreamerSubscription object. This is what determines what information we get back in the stream response. This object takes 4 parameters: mode, adapter, items, and fields. Below is a quick description of each.
Here’s an example of all these fields broken out using methods we previously created.
subscription = LightstreamerSubscription(
mode="MERGE",
adapter="PRICES",
items=[f"PRICE.{get_market_info()}"],
fields=["Bid", "Offer", "AuditId"]
)
Now that we have a subscription object, we need to provide a method to add as an event listener. In this case, we’ll make a method called on_item_update(update_item)
which takes in an object that has all the fields we requested as part of the subscription object setup. Below is a sample event listener method that simply prints out the fields we wanted. For your own usage, you would want to save these in some way to be used later on. We’ll also include the call that adds the method as an event listener.
def on_item_update(update_item):
print(update_item['values']['AuditId'])
print(update_item['values']['Offer'])
print(update_item['values']['Bid'])
subscription.addlistener(on_item_update)
All that’s left now is connecting to the server side of Lightstreamer, and connecting the subscription to that connection. After making these two calls, we’ll start getting updates every time the streaming API pushes our new values. Here’s how to do that
lightstreamer_client.connect()
sub_key = lightstreamer_client.subscribe(subscription)
As you can see, when subscribing, we get a key value. This can be used at a later time to kill the connection like so
lightstreamer_client.unsubscribe(sub_key)
lightstreamer_client.disconnect()
We finally have all the information we need to place a trade. To do so, we need to construct a JSON object that contains information about the trade we want to place. For this object, we’ll need data from a few different things. First, we need the Audit ID and either the Bid or Offer price from the streaming API (the price used is based on if this is a buy or sell operation). We will also need the market ID of what market we want to trade in, as well as your Trading Account ID from earlier. In this example, I’m requesting a static quantity of 10,000, but this could also be easily made into a variable that can be modified for each request. The same goes for the PriceTolerance value, which determines how much slippage in price you’re willing to allow. Here’s the full example place_trade()
method
def place_order():
body = {
"IfDone": [],
"Direction": "Buy",
"AuditId": {AUDIT_ID},
"MarketId": get_market_info(),
"OfferPrice": {ASK_PRICE},
"Currency": "USD",
"Quantity": 10000,
"PositionMethodId": 1,
"TradingAccountId": {YOUR_TRADING_ACCOUNT_ID},
"MarketName": "EUR/USD",
"PriceTolerance": 10
}
response = requests.post(
'https://ciapi.cityindex.com/TradingAPI/order/newtradeorder',
json=body,
headers={
"UserName": {YOUR_USERNAME},
"Session": {YOUR_SESSION_ID}
}
)
if response.status_code == 200:
print(response.json())
else:
print('An error occurred. Please try again', response.json())
Calling this method should successfully place a trade using your account.
If you’ve followed this full post, you should have everything you need to start placing trades in the market. Obviously, there’s plenty of space to improve, like putting this all in a class or a couple of different classes so you can have variables always at your disposal for things like your session ID, streaming data values, and anything else you might need. The goal of this post was to give some simple copy-paste lines of code that can be used together to get you up and running as fast as possible.
We love to make cool things with cool people. Have a project you’d like to collaborate on? Let’s chat!
Stay up to date on what BizStream is doing and keep in the loop on the latest in marketing & technology.