# ActTrader SDK for Python
Official Python SDK for ActTrader Trading API. This SDK provides a comprehensive interface to interact with ActTrader's REST API and WebSocket streaming services.
## Features
- 🔐 **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
## Installation
```bash
pip install acttrader-trading-sdk
```
## Quick Start
### Initialize the SDK
```python
from 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
```
## API Reference
### Authentication
#### Get Token
```python
# 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
```
#### Logout
```python
# Revoke current token
await client.auth.logout()
```
#### Reset Password
```python
# Reset user password (sent via email)
await client.auth.reset_password('user_login_id')
```
### Account Management
#### Get Accounts
```python
# 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 Password
```python
# Change user password
await client.account.change_password('old_password', 'new_password')
```
### Market Data
#### Get Instruments
```python
# 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 Symbols
```python
# 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 Detailed Symbol Information
```python
# 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
```python
# Get price shifts for instruments
result = await client.market.get_shifts()
shifts = result.result
```
### Trading
#### Place Market Order
```python
# 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** `lots` **or** `quantity`, not both
- `stop`, `limit`, `trail`, and `commentary` are all optional
- Symbol cache must be initialized to use lots: `await client.initialize_symbol_cache()`
#### Place Pending Order
```python
# 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/Limit Orders
```python
# 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 Order
```python
# Modify pending order
await client.trading.modify_order(
247668792, # Order ID
1.0080, # New price
2000 # New quantity
)
```
#### Cancel Order
```python
# Cancel pending order
await client.trading.cancel_order(247668792)
```
#### Close Trade
```python
# 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 Trade
```python
# Hedge an open position
result = await client.trading.hedge_trade(
247568770, # Trade ID
1000 # Quantity to hedge
)
```
#### Get Open Orders
```python
# 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 Open Trades
```python
# 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 Trade History
```python
# 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
```python
# Get removed orders history
result = await client.trading.get_removed_orders({
'from_date': '2021-04-01T00:00',
'till': '2021-04-30T23:59',
'account': 100
})
```
### Alerts (Deprecated)
⚠️ **Note:** The alert module is deprecated. Please check with ActTrader for alternative solutions.
```python
# 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)
)
```
### WebSocket Streaming
Real-time market data and trading events via WebSocket. The SDK supports **two separate WebSocket streams** for optimal performance and separation of concerns:
1. **Order Updates Stream** - Handles order events, trade events, account updates, and legacy ticker data
2. **Price Feed Stream** - Handles price feed messages with OHLC data
#### Dual WebSocket Setup (Recommended)
```python
# 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'])
```
#### Legacy Single WebSocket (Deprecated)
```python
# 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()
```
#### Message Formats
The SDK supports two WebSocket message formats:
**1. Legacy Ticker Format** (Order Updates)
```python
# 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)
```python
# 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 `ticker` event for order updates and basic price data
- Use `pricefeed` event for market data analysis with OHLC information
## Complete Example
```python
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())
```
## Error Handling
All API methods return a response object with the following structure:
```python
class ApiResponse:
success: bool
message: Optional[str] = None
result: Optional[Any] = None
```
Example error handling:
```python
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)
```
## Type Hints
This SDK is written with full Python type hints:
```python
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.result
```
## API Endpoints
All dates are in Eastern Time (EST/EDT)
### REST API
- Base URL: `http://rest-api.sysfx.com:18001/`
- API Version: v2
- Format: `/api/v2/{module}/{endpoint}`
### WebSocket
- URL: `ws://stream.sysfx.com:18002/`
- Connection: `ws://stream.sysfx.com:18002/ws?token={your_token}`
## Development
### Build from Source
```bash
# Install dependencies
pip install -r requirements.txt
# Install in development mode
pip install -e .
```
### Project Structure
```
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
```
## License
ISC
## Support
For API documentation and support, please contact ActTrader.
## Contributing
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).
Raw data
{
"_id": null,
"home_page": "https://github.com/acttrader/python-trading-sdk",
"name": "acttrader-trading-sdk",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "acttrader, trading, forex, api, sdk, trading-api, market-data, websocket, financial, broker",
"author": "Act",
"author_email": "support@acttrader.com",
"download_url": "https://files.pythonhosted.org/packages/06/ff/3fbccf8e91543db703abaeb060782781f94f13ea49a26675622c649099c1/acttrader_trading_sdk-1.0.1.tar.gz",
"platform": null,
"description": "# ActTrader SDK for Python\n\nOfficial Python SDK for ActTrader Trading API. This SDK provides a comprehensive interface to interact with ActTrader's REST API and WebSocket streaming services.\n\n## Features\n\n- \ud83d\udd10 **Authentication** - Digest authentication and token-based session management\n- \ud83d\udcb0 **Account Management** - Access account information and manage settings\n- \ud83d\udcca **Market Data** - Get real-time and historical market data, symbols, and instruments\n- \ud83d\udcc8 **Trading Operations** - Place, modify, and cancel orders; manage positions\n- \ud83c\udfaf **Lots-Based Trading** - Trade with lots (auto-converts to quantity using contract size)\n- \ud83d\udcbe **Symbol Cache** - Auto-refreshing symbol cache (24-hour intervals)\n- \ud83d\udd14 **Alerts** - Create and manage price alerts (deprecated)\n- \ud83c\udf0a **WebSocket Streaming** - Real-time market data and trading events\n- \ud83d\udcd8 **Type Hints** - Full Python type hints included\n- \u26a1 **Async Support** - Modern async/await API\n\n## Installation\n\n```bash\npip install acttrader-trading-sdk\n```\n\n## Quick Start\n\n### Initialize the SDK\n\n```python\nfrom acttrader import ActTrader\n\n# Option 1: Initialize with username and password for digest authentication\nclient = ActTrader(\n base_url='http://rest-api.sysfx.com:18001',\n ws_url='ws://stream.sysfx.com:18002', # Legacy: single WebSocket URL\n username='your_username',\n password='your_password'\n)\n\n# Option 2: Initialize with separate WebSocket URLs (recommended)\nclient = ActTrader(\n base_url='http://rest-api.sysfx.com:18001',\n order_ws_url='ws://order-stream.sysfx.com:18002', # Order updates stream\n price_feed_ws_url='ws://pricefeed-stream.sysfx.com:18003', # Price feed stream\n username='your_username',\n password='your_password'\n)\n\n# Option 3: Initialize with existing token\nclient = ActTrader(\n base_url='http://rest-api.sysfx.com:18001',\n order_ws_url='ws://order-stream.sysfx.com:18002',\n price_feed_ws_url='ws://pricefeed-stream.sysfx.com:18003',\n token='your_existing_token'\n)\n\n# Authenticate and initialize symbol cache (required for lots-based trading)\nawait client.auth.get_token(60)\nawait client.initialize_symbol_cache() # Auto-refreshes every 24 hours\n```\n\n## API Reference\n\n### Authentication\n\n#### Get Token\n\n```python\n# Get authentication token (requires username/password)\nresult = await client.auth.get_token(60) # 60 minutes lifetime\ntoken = result.result\nprint('Token:', token)\n\n# Token is automatically stored in the client\n```\n\n#### Logout\n\n```python\n# Revoke current token\nawait client.auth.logout()\n```\n\n#### Reset Password\n\n```python\n# Reset user password (sent via email)\nawait client.auth.reset_password('user_login_id')\n```\n\n### Account Management\n\n#### Get Accounts\n\n```python\n# Get all accounts for current user\nresult = await client.account.get_accounts()\naccounts = result.result\n\nfor account in accounts:\n print(f\"Account {account.AccountID}:\")\n print(f\" Balance: {account.Balance} {account.Currency}\")\n print(f\" Used Margin: {account.UsedMargin}\")\n```\n\n#### Change Password\n\n```python\n# Change user password\nawait client.account.change_password('old_password', 'new_password')\n```\n\n### Market Data\n\n#### Get Instruments\n\n```python\n# Get all active instruments\nresult = await client.market.get_instruments('Y')\ninstruments = result.result\n\nfor instrument in instruments:\n print(f\"{instrument.Name} ({instrument.Type})\")\n```\n\n#### Get Symbols\n\n```python\n# Get trading symbols with current prices\nresult = await client.market.get_symbols()\nsymbols = result.result\n\nfor symbol in symbols:\n print(f\"{symbol.Symbol}: Bid {symbol.Sell}, Ask {symbol.Buy}\")\n```\n\n#### Get Detailed Symbol Information\n\n```python\n# Get symbols with detailed information (margin, commission, etc.)\nresult = await client.market.get_symbols_detailed()\ndetails = result.result\n\nfor detail in details:\n print(f\"{detail.Pair_label}:\")\n print(f\" Contract Size: {detail.Contract_size}\")\n print(f\" Min Volume: {detail.Min_volume}\")\n print(f\" Margin Rate: {detail.Margin_settings.Rate}%\")\n```\n\n#### Get Price Shifts\n\n```python\n# Get price shifts for instruments\nresult = await client.market.get_shifts()\nshifts = result.result\n```\n\n### Trading\n\n#### Place Market Order\n\n```python\n# Simple order without stop/limit/trail\nresult = await client.trading.place_market_order({\n 'symbol': 'EURUSD',\n 'quantity': 100000, # Direct quantity\n 'side': 1, # 1 = buy, 0 = sell\n 'account': 100\n})\n\n# \ud83d\udd25 NEW: Order with LOTS (recommended for forex trading)\nresult2 = await client.trading.place_market_order({\n 'symbol': 'EURUSD',\n 'lots': 1.0, # SDK converts to quantity automatically\n 'side': 1,\n 'account': 100,\n 'stop': 1.0800, # Optional - stop loss\n 'limit': 1.1200, # Optional - take profit\n 'trail': 10, # Optional - trailing stop (in pips)\n 'commentary': 'Optional comment'\n})\n\n# Mini lot (0.1 lots)\nresult3 = await client.trading.place_market_order({\n 'symbol': 'EURUSD',\n 'lots': 0.1, # 0.1 lots = 10,000 quantity\n 'side': 1,\n 'account': 100\n})\n\nprint('Order placed:', result.result.OrderID)\n```\n\n**Note:** \n- Use **either** `lots` **or** `quantity`, not both\n- `stop`, `limit`, `trail`, and `commentary` are all optional\n- Symbol cache must be initialized to use lots: `await client.initialize_symbol_cache()`\n\n#### Place Pending Order\n\n```python\n# Place a pending order (Entry Stop or Entry Limit)\nresult = await client.trading.place_pending_order({\n 'symbol': 'EURUSD',\n 'quantity': 1000,\n 'side': 0, # 0 = sell, 1 = buy\n 'account': 100,\n 'price': 1.0950,\n 'stop': 1.1000,\n 'limit': 1.0900\n})\n```\n\n#### Place Stop/Limit Orders\n\n```python\n# Place stop loss on existing trade\nawait client.trading.place_stop({\n 'trade': 12345,\n 'price': 1.0800\n})\n\n# Place stop using pips instead of price\nawait client.trading.place_stop({\n 'trade': 12345,\n 'pips': 50\n})\n\n# Place take profit on existing trade\nawait client.trading.place_limit({\n 'trade': 12345,\n 'price': 1.1200\n})\n\n# Place trailing stop\nawait client.trading.place_trail({\n 'trade': 12345,\n 'trail': 10 # 10 pips\n})\n```\n\n#### Modify Order\n\n```python\n# Modify pending order\nawait client.trading.modify_order(\n 247668792, # Order ID\n 1.0080, # New price\n 2000 # New quantity\n)\n```\n\n#### Cancel Order\n\n```python\n# Cancel pending order\nawait client.trading.cancel_order(247668792)\n```\n\n#### Close Trade\n\n```python\n# Close open position\nresult = await client.trading.close_trade(\n 247568770, # Trade ID\n 1000, # Quantity to close\n 'N' # Hedge: 'Y' or 'N'\n)\n\nprint('Closing order:', result.result.OrderID)\n```\n\n#### Hedge Trade\n\n```python\n# Hedge an open position\nresult = await client.trading.hedge_trade(\n 247568770, # Trade ID\n 1000 # Quantity to hedge\n)\n```\n\n#### Get Open Orders\n\n```python\n# Get all open orders\nresult = await client.trading.get_open_orders()\norders = result.result\n\nfor order in orders:\n print(f\"Order {order.OrderID}:\")\n print(f\" {order.Symbol} {order.Side === 1 ? 'BUY' : 'SELL'}\")\n print(f\" Quantity: {order.Quantity} @ {order.Price}\")\n print(f\" Type: {order.Type}, Status: {order.Pending}\")\n```\n\n#### Get Open Trades\n\n```python\n# Get all open positions\nresult = await client.trading.get_open_trades()\ntrades = result.result\n\nfor trade in trades:\n print(f\"Trade {trade.TradeID}:\")\n print(f\" {trade.Symbol} {trade.Side === 1 ? 'BUY' : 'SELL'}\")\n print(f\" Quantity: {trade.Quantity} @ {trade.Price}\")\n print(f\" Commission: {trade.Commission}\")\n```\n\n#### Get Trade History\n\n```python\n# Get historical trades\nresult = await client.trading.get_trade_history({\n 'from_date': '2021-04-01T00:00',\n 'till': '2021-04-30T23:59',\n 'account': 100\n})\n\nhistory = result.result\n\nfor trade in history:\n print(f\"Trade {trade.TradeID}:\")\n print(f\" Open: {trade.OpenPrice} -> Close: {trade.ClosePrice}\")\n print(f\" P&L: {trade.ProfitLoss}\")\n```\n\n#### Get Removed Orders\n\n```python\n# Get removed orders history\nresult = await client.trading.get_removed_orders({\n 'from_date': '2021-04-01T00:00',\n 'till': '2021-04-30T23:59',\n 'account': 100\n})\n```\n\n### Alerts (Deprecated)\n\n\u26a0\ufe0f **Note:** The alert module is deprecated. Please check with ActTrader for alternative solutions.\n\n```python\n# Get active alerts\nresult = await client.alert.get_alerts()\n\n# Create alert\nalert_result = await client.alert.create_alert(\n 'EUR/USD', # Symbol\n 1.1800, # Price\n 'BID', # Type: 'BID' or 'ASK'\n 'Target price' # Commentary\n)\n\n# Modify alert\nawait client.alert.modify_alert(123, 1.1850, 'BID', 'Updated target')\n\n# Remove alert\nawait client.alert.remove_alert(123)\n\n# Get triggered alerts\ntriggered = await client.alert.get_triggered_alerts(\n '202109010000', # From date (YYYYMMDDHH24MI)\n '202109302359' # Till date (YYYYMMDDHH24MI)\n)\n```\n\n### WebSocket Streaming\n\nReal-time market data and trading events via WebSocket. The SDK supports **two separate WebSocket streams** for optimal performance and separation of concerns:\n\n1. **Order Updates Stream** - Handles order events, trade events, account updates, and legacy ticker data\n2. **Price Feed Stream** - Handles price feed messages with OHLC data\n\n#### Dual WebSocket Setup (Recommended)\n\n```python\n# Create separate streaming clients\norder_stream = client.stream_orders() # Order updates\nprice_stream = client.stream_price_feed() # Price feed data\n\n# Connect to order updates stream\norder_stream.on('connected', lambda: print('Order stream connected'))\norder_stream.on('order', lambda data: print('Order event:', data))\norder_stream.on('trade', lambda data: print('Trade event:', data))\n\nawait order_stream.connect()\nawait order_stream.subscribe(['EURUSD', 'GBPUSD'])\n\n# Connect to price feed stream\nprice_stream.on('connected', lambda: print('Price feed stream connected'))\nprice_stream.on('pricefeed', lambda data: print('Price feed with OHLC:', data))\n\nawait price_stream.connect()\nawait price_stream.subscribe(['EURUSD', 'GBPUSD'])\n```\n\n#### Legacy Single WebSocket (Deprecated)\n\n```python\n# Create streaming client (legacy approach)\nstream = client.stream()\n\n# Connect to WebSocket\nawait stream.connect()\n\n# Handle connection events\nstream.on('connected', lambda: print('Connected to streaming server'))\nstream.on('disconnected', lambda: print('Disconnected from streaming server'))\nstream.on('error', lambda error: print('WebSocket error:', error))\n\n# Subscribe to symbols\nawait stream.subscribe(['EURUSD', 'GBPUSD', 'USDJPY'])\n\n# Handle ticker updates (price changes) - Legacy format\nstream.on('ticker', lambda data: print('Ticker update:', data))\n\n# Handle price feed updates (new format with OHLC data)\nstream.on('pricefeed', lambda data: print('Price feed update:', data))\n\n# Handle order book updates\nstream.on('orderbook', lambda data: print('Order book update:', data))\n\n# Handle order events (insert/update/delete)\nstream.on('order', lambda data: print('Order event:', data))\n\n# Handle account balance updates\nstream.on('account', lambda data: print('Account update:', data))\n\n# Handle trade events\nstream.on('trade', lambda data: print('Trade event:', data))\n\n# Handle alert triggers\nstream.on('alert', lambda data: print('Alert triggered:', data))\n\n# Handle equity warnings\nstream.on('equity_warning', lambda data: print('Equity Warning!', data))\n\n# Unsubscribe from symbols\nawait stream.unsubscribe(['USDJPY'])\n\n# Disconnect\nawait stream.disconnect()\n```\n\n#### Message Formats\n\nThe SDK supports two WebSocket message formats:\n\n**1. Legacy Ticker Format** (Order Updates)\n```python\n# Event: 'ticker'\n{\n \"event\": \"ticker\",\n \"payload\": [\n {\n \"m\": \"EURUSD\",\n \"time\": \"2025-10-15T11:25:34.092Z\",\n \"bid\": 1.16295,\n \"ask\": 1.16302\n }\n ]\n}\n```\n\n**2. Price Feed Format** (Market Data with OHLC)\n```python\n# Event: 'pricefeed'\n{\n \"m\": \"ticker\",\n \"d\": [\n {\n \"m\": \"EURUSD\",\n \"time\": \"2025-10-15T11:25:34.092Z\",\n \"bid\": 1.16295,\n \"ask\": 1.16302,\n \"day_open\": 1.16064,\n \"day_high\": 1.16453,\n \"day_low\": 1.16012\n }\n ]\n}\n```\n\n**Usage Recommendation:**\n- Use `ticker` event for order updates and basic price data\n- Use `pricefeed` event for market data analysis with OHLC information\n\n## Complete Example\n\n```python\nimport asyncio\nfrom acttrader import ActTrader\n\nasync def main():\n # Initialize client\n client = ActTrader(\n base_url='http://rest-api.sysfx.com:18001',\n ws_url='ws://stream.sysfx.com:18002',\n username='your_username',\n password='your_password'\n )\n \n try:\n # Get authentication token\n token_result = await client.auth.get_token(60)\n print('Authenticated with token:', token_result.result)\n \n # Initialize symbol cache (required for lots-based trading)\n await client.initialize_symbol_cache()\n print('Symbol cache initialized')\n \n # Get accounts\n accounts_result = await client.account.get_accounts()\n accounts = accounts_result.result\n print(f'Found {len(accounts)} accounts')\n \n # Get market symbols\n symbols_result = await client.market.get_symbols()\n symbols = symbols_result.result\n print(f'Available symbols: {len(symbols)}')\n \n # Place a market order using LOTS (recommended)\n order_result = await client.trading.place_market_order({\n 'symbol': 'EURUSD',\n 'lots': 0.1, # 0.1 lots (auto-converted to quantity)\n 'side': 1, # Buy\n 'account': accounts[0].AccountID,\n 'stop': 1.0800, # Stop loss\n 'limit': 1.1200, # Take profit\n 'commentary': 'Test order'\n })\n print('Order placed:', order_result.result.OrderID)\n \n # Get open trades\n trades_result = await client.trading.get_open_trades()\n print('Open trades:', len(trades_result.result))\n \n # Start streaming\n stream = client.stream()\n \n def on_connected():\n print('Streaming connected')\n asyncio.create_task(stream.subscribe(['EURUSD', 'GBPUSD']))\n \n def on_ticker(data):\n print('Price update:', data)\n \n stream.on('connected', on_connected)\n stream.on('ticker', on_ticker)\n \n await stream.connect()\n \n # Keep process running\n await asyncio.sleep(30)\n \n await stream.disconnect()\n await client.auth.logout()\n \n except Exception as error:\n print('Error:', error)\n\nif __name__ == '__main__':\n asyncio.run(main())\n```\n\n## Error Handling\n\nAll API methods return a response object with the following structure:\n\n```python\nclass ApiResponse:\n success: bool\n message: Optional[str] = None\n result: Optional[Any] = None\n```\n\nExample error handling:\n\n```python\ntry:\n result = await client.trading.place_market_order({\n 'symbol': 'EURUSD',\n 'quantity': 1000,\n 'side': 1,\n 'account': 100\n })\n \n if result.success:\n print('Order ID:', result.result.OrderID)\n else:\n print('Order failed:', result.message)\nexcept Exception as error:\n print('API Error:', error)\n```\n\n## Type Hints\n\nThis SDK is written with full Python type hints:\n\n```python\nfrom acttrader import ActTrader, Account, Symbol, Order, Trade, OrderSide, OrderType, ApiResponse\n\n# Full type safety\nclient = ActTrader({...})\n\nresult: ApiResponse[List[Account]] = await client.account.get_accounts()\naccounts: List[Account] = result.result\n```\n\n## API Endpoints\n\nAll dates are in Eastern Time (EST/EDT)\n\n### REST API\n- Base URL: `http://rest-api.sysfx.com:18001/`\n- API Version: v2\n- Format: `/api/v2/{module}/{endpoint}`\n\n### WebSocket\n- URL: `ws://stream.sysfx.com:18002/`\n- Connection: `ws://stream.sysfx.com:18002/ws?token={your_token}`\n\n## Development\n\n### Build from Source\n\n```bash\n# Install dependencies\npip install -r requirements.txt\n\n# Install in development mode\npip install -e .\n```\n\n### Project Structure\n\n```\nacttrader-trading-sdk/\n\u251c\u2500\u2500 acttrader/\n\u2502 \u251c\u2500\u2500 __init__.py # Main SDK entry point\n\u2502 \u251c\u2500\u2500 main.py # Main ActTrader class\n\u2502 \u251c\u2500\u2500 client.py # HTTP client with authentication\n\u2502 \u251c\u2500\u2500 types.py # Python type definitions\n\u2502 \u251c\u2500\u2500 digest_auth.py # Digest authentication\n\u2502 \u251c\u2500\u2500 symbol_cache.py # Symbol cache functionality\n\u2502 \u2514\u2500\u2500 modules/\n\u2502 \u251c\u2500\u2500 __init__.py # Module exports\n\u2502 \u251c\u2500\u2500 auth.py # Authentication module\n\u2502 \u251c\u2500\u2500 account.py # Account management module\n\u2502 \u251c\u2500\u2500 market.py # Market data module\n\u2502 \u251c\u2500\u2500 trading.py # Trading operations module\n\u2502 \u251c\u2500\u2500 alert.py # Alerts module (deprecated)\n\u2502 \u2514\u2500\u2500 streaming.py # WebSocket streaming client\n\u251c\u2500\u2500 examples/ # Example scripts\n\u251c\u2500\u2500 tests/ # Test suite\n\u251c\u2500\u2500 setup.py # Package setup\n\u251c\u2500\u2500 requirements.txt # Dependencies\n\u2514\u2500\u2500 README.md # This file\n```\n\n## License\n\nISC\n\n## Support\n\nFor API documentation and support, please contact ActTrader.\n\n## Contributing\n\nContributions are welcome! Please ensure your code follows the existing style and includes appropriate tests.\n\n---\n\n**Note:** This SDK requires valid ActTrader credentials and access to ActTrader API servers. All dates/times are in Eastern Time (EST/EDT).\n",
"bugtrack_url": null,
"license": null,
"summary": "Official Python SDK for ActTrader Trading API",
"version": "1.0.1",
"project_urls": {
"Bug Reports": "https://github.com/acttrader/python-sdk/issues",
"Documentation": "https://github.com/acttrader/python-sdk#readme",
"Homepage": "https://github.com/acttrader/python-sdk",
"Source": "https://github.com/acttrader/python-sdk"
},
"split_keywords": [
"acttrader",
" trading",
" forex",
" api",
" sdk",
" trading-api",
" market-data",
" websocket",
" financial",
" broker"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "eec1c83bf03160365347354ca6e06fa49a3d54b34785faaf8525047fd4ef1d9c",
"md5": "5cb174e8f87fc7a7a490fbbe556bba79",
"sha256": "4f1ba7c225da23e26218487647df985738be4538fd40be402d09531b0f62f4c3"
},
"downloads": -1,
"filename": "acttrader_trading_sdk-1.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "5cb174e8f87fc7a7a490fbbe556bba79",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 29093,
"upload_time": "2025-10-24T08:35:56",
"upload_time_iso_8601": "2025-10-24T08:35:56.444682Z",
"url": "https://files.pythonhosted.org/packages/ee/c1/c83bf03160365347354ca6e06fa49a3d54b34785faaf8525047fd4ef1d9c/acttrader_trading_sdk-1.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "06ff3fbccf8e91543db703abaeb060782781f94f13ea49a26675622c649099c1",
"md5": "1999afc765c63b071799c14100e2e9bc",
"sha256": "6f3a7a753459ca53b43bf4e5ab8bf166fecf730bb21d1e38baf51e5cd97b9600"
},
"downloads": -1,
"filename": "acttrader_trading_sdk-1.0.1.tar.gz",
"has_sig": false,
"md5_digest": "1999afc765c63b071799c14100e2e9bc",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 31455,
"upload_time": "2025-10-24T08:35:58",
"upload_time_iso_8601": "2025-10-24T08:35:58.849668Z",
"url": "https://files.pythonhosted.org/packages/06/ff/3fbccf8e91543db703abaeb060782781f94f13ea49a26675622c649099c1/acttrader_trading_sdk-1.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-24 08:35:58",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "acttrader",
"github_project": "python-trading-sdk",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "requests",
"specs": [
[
">=",
"2.28.0"
]
]
},
{
"name": "websockets",
"specs": [
[
">=",
"11.0.0"
]
]
},
{
"name": "aiohttp",
"specs": [
[
">=",
"3.8.0"
]
]
},
{
"name": "asyncio-mqtt",
"specs": [
[
">=",
"0.13.0"
]
]
},
{
"name": "pydantic",
"specs": [
[
">=",
"2.0.0"
]
]
},
{
"name": "typing-extensions",
"specs": [
[
">=",
"4.0.0"
]
]
},
{
"name": "requests-ntlm",
"specs": [
[
">=",
"1.2.0"
]
]
},
{
"name": "python-dateutil",
"specs": [
[
">=",
"2.8.0"
]
]
},
{
"name": "ujson",
"specs": [
[
">=",
"5.0.0"
]
]
}
],
"lcname": "acttrader-trading-sdk"
}