ig-trading-api — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited ig-trading-api (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
You are an expert in the IG Markets Trading API for automated trading, building trading integrations, and creating trading applications using REST and Streaming APIs.
IG Labs provides REST and Streaming APIs for:
Supported Asset Classes: Indices, Forex, Commodities, Options, Shares
| Environment | Base URL |
|---|---|
| Live | https://api.ig.com/gateway/deal |
| Demo | https://demo-api.ig.com/gateway/deal |
All requests require these headers:
X-IG-API-KEY: your-api-key
Content-Type: application/json
Accept: application/json; charset=UTF-8
VERSION: 2#### Method 1: Session Tokens (v1/v2) - Recommended for most cases
POST /session
Content-Type: application/json
X-IG-API-KEY: your-api-key
VERSION: 2
{
"identifier": "your-username",
"password": "your-password"
}Response Headers:
CST: Client session tokenX-SECURITY-TOKEN: Account security tokenBoth tokens are valid for 6 hours, extending up to 72 hours with active use.
Subsequent Requests:
X-IG-API-KEY: your-api-key
CST: client-session-token
X-SECURITY-TOKEN: security-token#### Method 2: OAuth (v3) - For short-lived access
POST /session
Content-Type: application/json
X-IG-API-KEY: your-api-key
VERSION: 3
{
"identifier": "your-username",
"password": "your-password"
}Response:
{
"access_token": "702f6580-25c7-4c04-931d-6000efa824f8",
"refresh_token": "a9cec2d7-fd01-4d16-a2dd-7427ef6a471d",
"expires_in": "60"
}Subsequent Requests:
Authorization: Bearer access-token
IG-ACCOUNT-ID: your-account-idAccess tokens expire in ~60 seconds. Refresh tokens expire ~10 minutes after access token expiration.
#### Token Refresh
POST /session/refresh-token
X-IG-API-KEY: your-api-key
{
"refresh_token": "your-refresh-token"
}DELETE /session#### List Accounts
GET /accountsReturns all accounts for the logged-in client.
#### Get/Update Preferences
GET /accounts/preferences
PUT /accounts/preferences#### Activity History
GET /history/activity
GET /history/activity?from=2024-01-01T00:00:00&to=2024-01-31T23:59:59Supports FIQL filtering: ?filter=status==ACCEPTED;channel==PUBLIC_WEB_API
#### Transaction History
GET /history/transactions
GET /history/transactions?type=ALL&from=2024-01-01&to=2024-01-31#### Get All Open Positions
GET /positions#### Create OTC Position
POST /positions/otc
VERSION: 2
{
"epic": "IX.D.FTSE.DAILY.IP",
"direction": "BUY",
"size": 1,
"orderType": "MARKET",
"currencyCode": "GBP",
"forceOpen": true,
"guaranteedStop": false,
"stopLevel": null,
"stopDistance": 50,
"limitLevel": null,
"limitDistance": 100
}Direction values: BUY, SELL Order types: MARKET, LIMIT, QUOTE
#### Update Position
PUT /positions/otc/{dealId}
{
"stopLevel": 7100,
"limitLevel": 7500,
"trailingStop": false
}#### Close Position
DELETE /positions/otc/{dealId}
_method: DELETENote: Some implementations require _method: DELETE header.
#### Get All Working Orders
GET /workingorders#### Create Working Order
POST /workingorders/otc
{
"epic": "IX.D.FTSE.DAILY.IP",
"direction": "BUY",
"size": 1,
"level": 7000,
"type": "LIMIT",
"currencyCode": "GBP",
"goodTillDate": "2024-12-31T23:59:59",
"guaranteedStop": false,
"stopDistance": 50,
"limitDistance": 100
}Order types: LIMIT, STOP
#### Update/Delete Working Order
PUT /workingorders/otc/{dealId}
DELETE /workingorders/otc/{dealId}#### Search Markets
GET /markets?searchTerm=FTSE#### Get Market Details
GET /markets/{epic}
VERSION: 3#### Get Multiple Markets
GET /markets?epics=IX.D.FTSE.DAILY.IP,CS.D.GBPUSD.TODAY.IP#### Market Categories
GET /marketnavigation
GET /marketnavigation/{nodeId}#### Historical Prices
GET /prices/{epic}?resolution=HOUR&max=100
GET /prices/{epic}/{resolution}/{numPoints}
GET /prices/{epic}/{resolution}/{startDate}/{endDate}Resolutions: SECOND, MINUTE, MINUTE_2, MINUTE_3, MINUTE_5, MINUTE_10, MINUTE_15, MINUTE_30, HOUR, HOUR_2, HOUR_3, HOUR_4, DAY, WEEK, MONTH
Response:
{
"instrumentType": "INDICES",
"prices": [
{
"snapshotTime": "2024/01/15 14:00:00",
"openPrice": { "bid": 7500.0, "ask": 7501.0 },
"highPrice": { "bid": 7520.0, "ask": 7521.0 },
"lowPrice": { "bid": 7490.0, "ask": 7491.0 },
"closePrice": { "bid": 7510.0, "ask": 7511.0 },
"lastTradedVolume": 1000
}
]
}#### List Watchlists
GET /watchlists#### Get Watchlist
GET /watchlists/{watchlistId}#### Create Watchlist
POST /watchlists
{
"name": "My Watchlist",
"epics": ["IX.D.FTSE.DAILY.IP", "CS.D.GBPUSD.TODAY.IP"]
}#### Add/Remove Items
PUT /watchlists/{watchlistId}
{
"epic": "IX.D.DAX.DAILY.IP"
}DELETE /watchlists/{watchlistId}/{epic}GET /clientsentiment/{marketId}
GET /clientsentiment?marketIds=FTSE,DAX,GBPUSDResponse:
{
"marketId": "FTSE",
"longPositionPercentage": 65.5,
"shortPositionPercentage": 34.5
}After creating/modifying positions, confirm the deal status:
GET /confirms/{dealReference}Deal Status values: ACCEPTED, REJECTED
The Streaming API uses Lightstreamer for real-time data.
import { LightstreamerClient, Subscription } from 'lightstreamer-client-web';
// Get credentials from REST session
const session = await fetch('https://demo-api.ig.com/gateway/deal/session', {
method: 'POST',
headers: {
'X-IG-API-KEY': apiKey,
'Content-Type': 'application/json',
'VERSION': '2'
},
body: JSON.stringify({ identifier: username, password: password })
});
const cst = session.headers.get('CST');
const xSecurityToken = session.headers.get('X-SECURITY-TOKEN');
const data = await session.json();
const lightstreamerEndpoint = data.lightstreamerEndpoint;
// Connect to Lightstreamer
const client = new LightstreamerClient(lightstreamerEndpoint);
client.connectionDetails.setUser(data.currentAccountId);
client.connectionDetails.setPassword(`CST-${cst}|XST-${xSecurityToken}`);
client.addListener({
onStatusChange: (status) => console.log('Connection status:', status)
});
client.connect();Note: Streaming API does NOT support OAuth tokens. Use CST/X-SECURITY-TOKEN.
Subscription Modes:
MERGE: Consolidated updates (prices, account data)DISTINCT: Individual updates (trades)Limits: Up to 40 simultaneous subscriptions per connection.
const subscription = new Subscription(
'MERGE',
['MARKET:IX.D.FTSE.DAILY.IP'],
['BID', 'OFFER', 'HIGH', 'LOW', 'MID_OPEN', 'CHANGE', 'CHANGE_PCT', 'UPDATE_TIME']
);
subscription.addListener({
onItemUpdate: (update) => {
console.log('Bid:', update.getValue('BID'));
console.log('Offer:', update.getValue('OFFER'));
}
});
client.subscribe(subscription);// Balance updates
const accountSub = new Subscription(
'MERGE',
['ACCOUNT:XXXXX'],
['PNL', 'DEPOSIT', 'AVAILABLE_CASH', 'FUNDS', 'MARGIN', 'EQUITY']
);
// Trade confirmations
const tradeSub = new Subscription(
'DISTINCT',
['TRADE:XXXXX'],
['CONFIRMS', 'OPU', 'WOU']
);const chartSub = new Subscription(
'MERGE',
['CHART:IX.D.FTSE.DAILY.IP:MINUTE'],
['BID_OPEN', 'BID_HIGH', 'BID_LOW', 'BID_CLOSE', 'OFR_OPEN', 'OFR_HIGH', 'OFR_LOW', 'OFR_CLOSE', 'CONS_END', 'UTM']
);Chart Scales: SECOND, 1MINUTE, 5MINUTE, HOUR
client.unsubscribe(subscription);client.disconnect();import requests
BASE_URL = 'https://demo-api.ig.com/gateway/deal'
API_KEY = 'your-api-key'
# Login
session = requests.Session()
session.headers.update({
'X-IG-API-KEY': API_KEY,
'Content-Type': 'application/json',
'Accept': 'application/json',
'VERSION': '2'
})
auth_response = session.post(f'{BASE_URL}/session', json={
'identifier': 'your-username',
'password': 'your-password'
})
session.headers.update({
'CST': auth_response.headers['CST'],
'X-SECURITY-TOKEN': auth_response.headers['X-SECURITY-TOKEN']
})
# Get open positions
positions = session.get(f'{BASE_URL}/positions').json()
print('Open positions:', positions)
# Get historical prices
prices = session.get(f'{BASE_URL}/prices/IX.D.FTSE.DAILY.IP?resolution=HOUR&max=24').json()
print('Prices:', prices)
# Place a trade
trade = session.post(f'{BASE_URL}/positions/otc', json={
'epic': 'IX.D.FTSE.DAILY.IP',
'direction': 'BUY',
'size': 1,
'orderType': 'MARKET',
'currencyCode': 'GBP',
'forceOpen': True,
'guaranteedStop': False,
'stopDistance': 50,
'limitDistance': 100
}).json()
print('Trade reference:', trade['dealReference'])
# Confirm deal
confirm = session.get(f'{BASE_URL}/confirms/{trade["dealReference"]}').json()
print('Deal status:', confirm['dealStatus'])
# Logout
session.delete(f'{BASE_URL}/session')const fetch = require('node-fetch');
const { LightstreamerClient, Subscription } = require('lightstreamer-client-node');
const BASE_URL = 'https://demo-api.ig.com/gateway/deal';
const API_KEY = 'your-api-key';
async function main() {
// Login
const loginResponse = await fetch(`${BASE_URL}/session`, {
method: 'POST',
headers: {
'X-IG-API-KEY': API_KEY,
'Content-Type': 'application/json',
'VERSION': '2'
},
body: JSON.stringify({
identifier: 'your-username',
password: 'your-password'
})
});
const cst = loginResponse.headers.get('CST');
const xSecurityToken = loginResponse.headers.get('X-SECURITY-TOKEN');
const sessionData = await loginResponse.json();
// Setup authenticated fetch
const authFetch = (url, options = {}) => {
return fetch(url, {
...options,
headers: {
'X-IG-API-KEY': API_KEY,
'CST': cst,
'X-SECURITY-TOKEN': xSecurityToken,
'Content-Type': 'application/json',
...options.headers
}
});
};
// Get markets
const markets = await authFetch(`${BASE_URL}/markets?searchTerm=FTSE`);
console.log('Markets:', await markets.json());
// Setup streaming
const client = new LightstreamerClient(sessionData.lightstreamerEndpoint);
client.connectionDetails.setUser(sessionData.currentAccountId);
client.connectionDetails.setPassword(`CST-${cst}|XST-${xSecurityToken}`);
client.addListener({
onStatusChange: (status) => console.log('Stream status:', status)
});
client.connect();
// Subscribe to prices
const priceSub = new Subscription(
'MERGE',
['MARKET:IX.D.FTSE.DAILY.IP'],
['BID', 'OFFER', 'UPDATE_TIME']
);
priceSub.addListener({
onItemUpdate: (update) => {
console.log(`${update.getValue('UPDATE_TIME')} - Bid: ${update.getValue('BID')}, Offer: ${update.getValue('OFFER')}`);
}
});
client.subscribe(priceSub);
}
main().catch(console.error);from trading_ig import IGService
from trading_ig.config import config
# Configure credentials via environment variables or config
# IG_SERVICE_USERNAME, IG_SERVICE_PASSWORD, IG_SERVICE_API_KEY, IG_SERVICE_ACC_TYPE
ig = IGService(
config.username,
config.password,
config.api_key,
config.acc_type # 'DEMO' or 'LIVE'
)
ig.create_session()
# Get open positions
positions = ig.fetch_open_positions()
print(positions)
# Get historical prices
prices = ig.fetch_historical_prices_by_epic_and_num_points(
epic='IX.D.FTSE.DAILY.IP',
resolution='H',
numpoints=100
)
print(prices)
# Close session
ig.logout(){
"errorCode": "error.public-api.exceeded-api-key-allowance"
}| Error Code | Description |
|---|---|
error.security.invalid-credentials | Invalid username/password |
error.security.invalid-api-key | Invalid API key |
error.security.api-key-disabled | API key has been disabled |
error.security.invalid-session | Session has expired |
error.public-api.exceeded-api-key-allowance | Rate limit exceeded |
error.request.invalid-date-range | Invalid date range in request |
error.position.notional-value.limit-exceeded | Position size too large |
error.market.closed | Market is closed |
error.dealing.direction-not-allowed | Cannot trade in this direction |
error.public-api.exceeded-api-key-allowanceList endpoints return pagination metadata:
{
"metadata": {
"paging": {
"next": "/history/activity?version=3&from=2024-01-01&to=2024-01-31&pageSize=50&offset=50",
"size": 50
}
}
}All date/time values are ISO 8601 formatted and in UTC timezone unless otherwise stated.
Examples:
2024-01-15T14:30:002024/01/15 14:30:00 (in some price responses)Specify API version via VERSION header:
VERSION: 2Different endpoints support different versions. Check documentation for version-specific features:
/confirms/{dealReference} after trades~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.