Official Python SDK for ActTrader Trading API. This SDK provides a comprehensive interface to interact with ActTrader's REST API and WebSocket streaming services.
- 🔐 Authentication - Digest authentication and token-based session management
- 💰 Account Management - Access account information and manage settings
- 📊 Market Data - Get real-time and historical market data, symbols, and instruments
- 📈 Trading Operations - Place, modify, and cancel orders; manage positions
- 🎯 Lots-Based Trading - Trade with lots (auto-converts to quantity using contract size)
- 💾 Symbol Cache - Auto-refreshing symbol cache (24-hour intervals)
- 🔔 Alerts - Create and manage price alerts (deprecated)
- 🌊 WebSocket Streaming - Real-time market data and trading events
- 📘 Type Hints - Full Python type hints included
- ⚡ Async Support - Modern async/await API
pip install acttrader-trading-sdkfrom acttrader import ActTrader
# Option 1: Initialize with username and password for digest authentication
client = ActTrader(
base_url='http://rest-api.sysfx.com:18001',
ws_url='ws://stream.sysfx.com:18002', # Legacy: single WebSocket URL
username='your_username',
password='your_password'
)
# Option 2: Initialize with separate WebSocket URLs (recommended)
client = ActTrader(
base_url='http://rest-api.sysfx.com:18001',
order_ws_url='ws://order-stream.sysfx.com:18002', # Order updates stream
price_feed_ws_url='ws://pricefeed-stream.sysfx.com:18003', # Price feed stream
username='your_username',
password='your_password'
)
# Option 3: Initialize with existing token
client = ActTrader(
base_url='http://rest-api.sysfx.com:18001',
order_ws_url='ws://order-stream.sysfx.com:18002',
price_feed_ws_url='ws://pricefeed-stream.sysfx.com:18003',
token='your_existing_token'
)
# Authenticate and initialize symbol cache (required for lots-based trading)
await client.auth.get_token(60)
await client.initialize_symbol_cache() # Auto-refreshes every 24 hours# Get authentication token (requires username/password)
result = await client.auth.get_token(60) # 60 minutes lifetime
token = result.result
print('Token:', token)
# Token is automatically stored in the client# Revoke current token
await client.auth.logout()# Reset user password (sent via email)
await client.auth.reset_password('user_login_id')# Get all accounts for current user
result = await client.account.get_accounts()
accounts = result.result
for account in accounts:
print(f"Account {account.AccountID}:")
print(f" Balance: {account.Balance} {account.Currency}")
print(f" Used Margin: {account.UsedMargin}")# Change user password
await client.account.change_password('old_password', 'new_password')# Get all active instruments
result = await client.market.get_instruments('Y')
instruments = result.result
for instrument in instruments:
print(f"{instrument.Name} ({instrument.Type})")# Get trading symbols with current prices
result = await client.market.get_symbols()
symbols = result.result
for symbol in symbols:
print(f"{symbol.Symbol}: Bid {symbol.Sell}, Ask {symbol.Buy}")# Get symbols with detailed information (margin, commission, etc.)
result = await client.market.get_symbols_detailed()
details = result.result
for detail in details:
print(f"{detail.Pair_label}:")
print(f" Contract Size: {detail.Contract_size}")
print(f" Min Volume: {detail.Min_volume}")
print(f" Margin Rate: {detail.Margin_settings.Rate}%")# Get price shifts for instruments
result = await client.market.get_shifts()
shifts = result.result# Simple order without stop/limit/trail
result = await client.trading.place_market_order({
'symbol': 'EURUSD',
'quantity': 100000, # Direct quantity
'side': 1, # 1 = buy, 0 = sell
'account': 100
})
# 🔥 NEW: Order with LOTS (recommended for forex trading)
result2 = await client.trading.place_market_order({
'symbol': 'EURUSD',
'lots': 1.0, # SDK converts to quantity automatically
'side': 1,
'account': 100,
'stop': 1.0800, # Optional - stop loss
'limit': 1.1200, # Optional - take profit
'trail': 10, # Optional - trailing stop (in pips)
'commentary': 'Optional comment'
})
# Mini lot (0.1 lots)
result3 = await client.trading.place_market_order({
'symbol': 'EURUSD',
'lots': 0.1, # 0.1 lots = 10,000 quantity
'side': 1,
'account': 100
})
print('Order placed:', result.result.OrderID)Note:
- Use either
lotsorquantity, not both stop,limit,trail, andcommentaryare all optional- Symbol cache must be initialized to use lots:
await client.initialize_symbol_cache()
# Place a pending order (Entry Stop or Entry Limit)
result = await client.trading.place_pending_order({
'symbol': 'EURUSD',
'quantity': 1000,
'side': 0, # 0 = sell, 1 = buy
'account': 100,
'price': 1.0950,
'stop': 1.1000,
'limit': 1.0900
})# Place stop loss on existing trade
await client.trading.place_stop({
'trade': 12345,
'price': 1.0800
})
# Place stop using pips instead of price
await client.trading.place_stop({
'trade': 12345,
'pips': 50
})
# Place take profit on existing trade
await client.trading.place_limit({
'trade': 12345,
'price': 1.1200
})
# Place trailing stop
await client.trading.place_trail({
'trade': 12345,
'trail': 10 # 10 pips
})# Modify pending order
await client.trading.modify_order(
247668792, # Order ID
1.0080, # New price
2000 # New quantity
)# Cancel pending order
await client.trading.cancel_order(247668792)# Close open position
result = await client.trading.close_trade(
247568770, # Trade ID
1000, # Quantity to close
'N' # Hedge: 'Y' or 'N'
)
print('Closing order:', result.result.OrderID)# Hedge an open position
result = await client.trading.hedge_trade(
247568770, # Trade ID
1000 # Quantity to hedge
)# Get all open orders
result = await client.trading.get_open_orders()
orders = result.result
for order in orders:
print(f"Order {order.OrderID}:")
print(f" {order.Symbol} {order.Side === 1 ? 'BUY' : 'SELL'}")
print(f" Quantity: {order.Quantity} @ {order.Price}")
print(f" Type: {order.Type}, Status: {order.Pending}")# Get all open positions
result = await client.trading.get_open_trades()
trades = result.result
for trade in trades:
print(f"Trade {trade.TradeID}:")
print(f" {trade.Symbol} {trade.Side === 1 ? 'BUY' : 'SELL'}")
print(f" Quantity: {trade.Quantity} @ {trade.Price}")
print(f" Commission: {trade.Commission}")# Get historical trades
result = await client.trading.get_trade_history({
'from_date': '2021-04-01T00:00',
'till': '2021-04-30T23:59',
'account': 100
})
history = result.result
for trade in history:
print(f"Trade {trade.TradeID}:")
print(f" Open: {trade.OpenPrice} -> Close: {trade.ClosePrice}")
print(f" P&L: {trade.ProfitLoss}")# Get removed orders history
result = await client.trading.get_removed_orders({
'from_date': '2021-04-01T00:00',
'till': '2021-04-30T23:59',
'account': 100
})# Get active alerts
result = await client.alert.get_alerts()
# Create alert
alert_result = await client.alert.create_alert(
'EUR/USD', # Symbol
1.1800, # Price
'BID', # Type: 'BID' or 'ASK'
'Target price' # Commentary
)
# Modify alert
await client.alert.modify_alert(123, 1.1850, 'BID', 'Updated target')
# Remove alert
await client.alert.remove_alert(123)
# Get triggered alerts
triggered = await client.alert.get_triggered_alerts(
'202109010000', # From date (YYYYMMDDHH24MI)
'202109302359' # Till date (YYYYMMDDHH24MI)
)Real-time market data and trading events via WebSocket. The SDK supports two separate WebSocket streams for optimal performance and separation of concerns:
- Order Updates Stream - Handles order events, trade events, account updates, and legacy ticker data
- Price Feed Stream - Handles price feed messages with OHLC data
# Create separate streaming clients
order_stream = client.stream_orders() # Order updates
price_stream = client.stream_price_feed() # Price feed data
# Connect to order updates stream
order_stream.on('connected', lambda: print('Order stream connected'))
order_stream.on('order', lambda data: print('Order event:', data))
order_stream.on('trade', lambda data: print('Trade event:', data))
await order_stream.connect()
await order_stream.subscribe(['EURUSD', 'GBPUSD'])
# Connect to price feed stream
price_stream.on('connected', lambda: print('Price feed stream connected'))
price_stream.on('pricefeed', lambda data: print('Price feed with OHLC:', data))
await price_stream.connect()
await price_stream.subscribe(['EURUSD', 'GBPUSD'])# Create streaming client (legacy approach)
stream = client.stream()
# Connect to WebSocket
await stream.connect()
# Handle connection events
stream.on('connected', lambda: print('Connected to streaming server'))
stream.on('disconnected', lambda: print('Disconnected from streaming server'))
stream.on('error', lambda error: print('WebSocket error:', error))
# Subscribe to symbols
await stream.subscribe(['EURUSD', 'GBPUSD', 'USDJPY'])
# Handle ticker updates (price changes) - Legacy format
stream.on('ticker', lambda data: print('Ticker update:', data))
# Handle price feed updates (new format with OHLC data)
stream.on('pricefeed', lambda data: print('Price feed update:', data))
# Handle order book updates
stream.on('orderbook', lambda data: print('Order book update:', data))
# Handle order events (insert/update/delete)
stream.on('order', lambda data: print('Order event:', data))
# Handle account balance updates
stream.on('account', lambda data: print('Account update:', data))
# Handle trade events
stream.on('trade', lambda data: print('Trade event:', data))
# Handle alert triggers
stream.on('alert', lambda data: print('Alert triggered:', data))
# Handle equity warnings
stream.on('equity_warning', lambda data: print('Equity Warning!', data))
# Unsubscribe from symbols
await stream.unsubscribe(['USDJPY'])
# Disconnect
await stream.disconnect()The SDK supports two WebSocket message formats:
1. Legacy Ticker Format (Order Updates)
# Event: 'ticker'
{
"event": "ticker",
"payload": [
{
"m": "EURUSD",
"time": "2025-10-15T11:25:34.092Z",
"bid": 1.16295,
"ask": 1.16302
}
]
}2. Price Feed Format (Market Data with OHLC)
# Event: 'pricefeed'
{
"m": "ticker",
"d": [
{
"m": "EURUSD",
"time": "2025-10-15T11:25:34.092Z",
"bid": 1.16295,
"ask": 1.16302,
"day_open": 1.16064,
"day_high": 1.16453,
"day_low": 1.16012
}
]
}Usage Recommendation:
- Use
tickerevent for order updates and basic price data - Use
pricefeedevent for market data analysis with OHLC information
import asyncio
from acttrader import ActTrader
async def main():
# Initialize client
client = ActTrader(
base_url='http://rest-api.sysfx.com:18001',
ws_url='ws://stream.sysfx.com:18002',
username='your_username',
password='your_password'
)
try:
# Get authentication token
token_result = await client.auth.get_token(60)
print('Authenticated with token:', token_result.result)
# Initialize symbol cache (required for lots-based trading)
await client.initialize_symbol_cache()
print('Symbol cache initialized')
# Get accounts
accounts_result = await client.account.get_accounts()
accounts = accounts_result.result
print(f'Found {len(accounts)} accounts')
# Get market symbols
symbols_result = await client.market.get_symbols()
symbols = symbols_result.result
print(f'Available symbols: {len(symbols)}')
# Place a market order using LOTS (recommended)
order_result = await client.trading.place_market_order({
'symbol': 'EURUSD',
'lots': 0.1, # 0.1 lots (auto-converted to quantity)
'side': 1, # Buy
'account': accounts[0].AccountID,
'stop': 1.0800, # Stop loss
'limit': 1.1200, # Take profit
'commentary': 'Test order'
})
print('Order placed:', order_result.result.OrderID)
# Get open trades
trades_result = await client.trading.get_open_trades()
print('Open trades:', len(trades_result.result))
# Start streaming
stream = client.stream()
def on_connected():
print('Streaming connected')
asyncio.create_task(stream.subscribe(['EURUSD', 'GBPUSD']))
def on_ticker(data):
print('Price update:', data)
stream.on('connected', on_connected)
stream.on('ticker', on_ticker)
await stream.connect()
# Keep process running
await asyncio.sleep(30)
await stream.disconnect()
await client.auth.logout()
except Exception as error:
print('Error:', error)
if __name__ == '__main__':
asyncio.run(main())All API methods return a response object with the following structure:
class ApiResponse:
success: bool
message: Optional[str] = None
result: Optional[Any] = NoneExample error handling:
try:
result = await client.trading.place_market_order({
'symbol': 'EURUSD',
'quantity': 1000,
'side': 1,
'account': 100
})
if result.success:
print('Order ID:', result.result.OrderID)
else:
print('Order failed:', result.message)
except Exception as error:
print('API Error:', error)This SDK is written with full Python type hints:
from acttrader import ActTrader, Account, Symbol, Order, Trade, OrderSide, OrderType, ApiResponse
# Full type safety
client = ActTrader({...})
result: ApiResponse[List[Account]] = await client.account.get_accounts()
accounts: List[Account] = result.resultAll dates are in Eastern Time (EST/EDT)
- Base URL:
http://rest-api.sysfx.com:18001/ - API Version: v2
- Format:
/api/v2/{module}/{endpoint}
- URL:
ws://stream.sysfx.com:18002/ - Connection:
ws://stream.sysfx.com:18002/ws?token={your_token}
# Install dependencies
pip install -r requirements.txt
# Install in development mode
pip install -e .acttrader-trading-sdk/
├── acttrader/
│ ├── __init__.py # Main SDK entry point
│ ├── main.py # Main ActTrader class
│ ├── client.py # HTTP client with authentication
│ ├── types.py # Python type definitions
│ ├── digest_auth.py # Digest authentication
│ ├── symbol_cache.py # Symbol cache functionality
│ └── modules/
│ ├── __init__.py # Module exports
│ ├── auth.py # Authentication module
│ ├── account.py # Account management module
│ ├── market.py # Market data module
│ ├── trading.py # Trading operations module
│ ├── alert.py # Alerts module (deprecated)
│ └── streaming.py # WebSocket streaming client
├── examples/ # Example scripts
├── tests/ # Test suite
├── setup.py # Package setup
├── requirements.txt # Dependencies
└── README.md # This file
ISC
For API documentation and support, please contact ActTrader.
Contributions are welcome! Please ensure your code follows the existing style and includes appropriate tests.
Note: This SDK requires valid ActTrader credentials and access to ActTrader API servers. All dates/times are in Eastern Time (EST/EDT).