Inter-Strategy Live Trading Communication
Feature Overview
The inter-strategy live trading communication feature allows different live trading strategies to share data and synchronize states. Through a channel mechanism, one live trading instance can broadcast its state data to other live trading instances, enabling cross-instance, cross-custodian, and cross-server data communication.
Core Concepts
- Channel: Each live trading instance has an independent channel, with the channel ID being the live trading instance ID
- Broadcaster: Live trading instance that publishes data on a channel using the
SetChannelData()function - Subscriber: Live trading instance that subscribes to other live trading instance channel data using the
GetChannelData()function - State Overwrite: Only the latest state is saved on the channel, new data overwrites old data, not a message queue
Key Features
- Non-blocking Communication: All function calls are non-blocking and do not affect the main strategy flow
- Cross-platform Support: Supports data transmission across live trading instances, custodians, and servers
- Multi-channel Subscription: A single live trading instance can simultaneously subscribe to multiple different live trading instance channels
- Flexible Data Format: Supports any JSON-serializable data structure
Application Scenarios
- Master-Slave Strategy Coordination: Master strategy analyzes market and broadcasts signals, slave strategies receive signals and execute trades
- Multi-account Synchronization: Synchronize trading signals and position information across multiple trading accounts
- Strategy Monitoring: Monitoring strategies broadcast operational status, monitoring live trading instances subscribe and display or alert
- Data Sharing: Share market analysis, indicator calculation results to avoid redundant calculations
Basic Usage
Examples
-
Broadcaster Example - Publishing Market Data
javascriptfunction main() { var updateId = 0 var robotId = _G() // Get current live trading ID while(true) { // Get market data var ticker = exchange.GetTicker("BTC_USDT") if (!ticker) { Sleep(5000) continue } // Prepare channel state data var channelState = { robotId: robotId, updateId: ++updateId, timestamp: Date.now(), symbol: "BTC_USDT", lastPrice: ticker.Last, volume: ticker.Volume, high: ticker.High, low: ticker.Low } // Publish latest state on channel (overwrite old state) SetChannelData(channelState) // Display current channel state LogStatus("Channel Broadcaster [Bot ID: " + robotId + "]\n" + "Update ID: #" + channelState.updateId + "\n" + "Time: " + _D(channelState.timestamp) + "\n" + "Symbol: " + channelState.symbol + "\n" + "Last Price: $" + channelState.lastPrice.toFixed(2)) Sleep(60000) // Update channel state every minute } }pythondef main(): updateId = 0 robotId = _G() # Get current live trading ID while True: # Get market data ticker = exchange.GetTicker("BTC_USDT") if not ticker: Sleep(5000) continue # Prepare channel state data channelState = { "robotId": robotId, "updateId": updateId + 1, "timestamp": time.time() * 1000, "symbol": "BTC_USDT", "lastPrice": ticker["Last"], "volume": ticker["Volume"], "high": ticker["High"], "low": ticker["Low"] } updateId += 1 # Publish latest state on channel (overwrite old state) SetChannelData(channelState) # Display current channel state LogStatus("Channel Broadcaster [Bot ID: {}]\n".format(robotId) + "Update ID: #{}\n".format(channelState["updateId"]) + "Time: {}\n".format(_D(channelState["timestamp"])) + "Last Price: ${:.2f}".format(channelState["lastPrice"])) Sleep(60000) # Update channel state every minutec++ -
Subscriber Example - Subscribe to Multiple Channels
javascriptfunction main() { // Two channel IDs to subscribe to (modify according to actual situation) var channelId1 = "632799" // Live trading ID for channel 1 var channelId2 = "632800" // Live trading ID for channel 2 while(true) { // Subscribe to current state of channel 1 var state1 = GetChannelData(channelId1) // Subscribe to current state of channel 2 var state2 = GetChannelData(channelId2) // Build status display var statusMsg = "Channel Subscriber - Current Subscription Status\n\n" // Display channel 1 status statusMsg += "═══ Channel 1 [" + channelId1 + "] ═══\n" if (state1 !== null) { statusMsg += "Update ID: #" + state1.updateId + "\n" statusMsg += "Time: " + _D(state1.timestamp) + "\n" statusMsg += "Trading Pair: " + state1.symbol + "\n" statusMsg += "Last Price: $" + state1.lastPrice.toFixed(2) + "\n" } else { statusMsg += "Status: Waiting... (first call returns null)\n" } statusMsg += "\n" // Display channel 2 status statusMsg += "═══ Channel 2 [" + channelId2 + "] ═══\n" if (state2 !== null) { statusMsg += "Update ID: #" + state2.updateId + "\n" statusMsg += "Time: " + _D(state2.timestamp) + "\n" statusMsg += "Last Price: $" + state2.lastPrice.toFixed(2) + "\n" } else { statusMsg += "Status: Waiting... (first call returns null)\n" } LogStatus(statusMsg) Sleep(5000) // Subscribe to channels every 5 seconds } }pythondef main(): # Two channel IDs to subscribe to (modify according to actual situation) channelId1 = "632799" # Live trading ID for channel 1 channelId2 = "632800" # Live trading ID for channel 2 while True: # Subscribe to current state of channel 1 state1 = GetChannelData(channelId1) # Subscribe to current state of channel 2 state2 = GetChannelData(channelId2) # Build status display statusMsg = "Channel Subscriber - Current Subscription Status\n\n" # Display channel 1 status statusMsg += "═══ Channel 1 [{}] ═══\n".format(channelId1) if state1 is not None: statusMsg += "Update ID: #{}\n".format(state1["updateId"]) statusMsg += "Time: {}\n".format(_D(state1["timestamp"])) statusMsg += "Last Price: ${:.2f}\n".format(state1["lastPrice"]) else: statusMsg += "Status: Waiting... (first call returns None)\n" statusMsg += "\n" # Display channel 2 status statusMsg += "═══ Channel 2 [{}] ═══\n".format(channelId2) if state2 is not None: statusMsg += "Update ID: #{}\n".format(state2["updateId"]) statusMsg += "Time: {}\n".format(_D(state2["timestamp"])) statusMsg += "Last Price: ${:.2f}\n".format(state2["lastPrice"]) else: statusMsg += "Status: Waiting... (first call returns None)\n" LogStatus(statusMsg) Sleep(5000) # Subscribe to channels every 5 secondsc++ -
Practical Application Scenarios
### Scenario 1: Master-Slave Strategy Coordinated Trading
Master Strategy (Signal Broadcasting Side)
javascriptfunction main() { var robotId = _G() Log("Main strategy started, Bot ID:", robotId) while(true) { // Analyze market and generate trading signals var records = exchange.GetRecords("BTC_USDT") if (!records || records.length < 20) { Sleep(5000) continue } // Simple moving average strategy var ma5 = TA.MA(records, 5) var ma20 = TA.MA(records, 20) var signal = "HOLD" if (ma5[ma5.length-1] > ma20[ma20.length-1] && ma5[ma5.length-2] <= ma20[ma20.length-2]) { signal = "BUY" } else if (ma5[ma5.length-1] < ma20[ma20.length-1] && ma5[ma5.length-2] >= ma20[ma20.length-2]) { signal = "SELL" } // Broadcast trading signal var signalData = { timestamp: Date.now(), symbol: "BTC_USDT", signal: signal, price: records[records.length-1].Close, ma5: ma5[ma5.length-1], ma20: ma20[ma20.length-1] } SetChannelData(signalData) LogStatus("Main Strategy - Signal Broadcast\n" + "Signal: " + signal + "\n" + "Price: $" + signalData.price.toFixed(2) + "\n" + "MA5: " + signalData.ma5.toFixed(2) + "\n" + "MA20: " + signalData.ma20.toFixed(2)) Sleep(60000) } }pythondef main(): robotId = _G() Log("Main strategy started, Bot ID:", robotId) while True: # Analyze market and generate trading signals records = exchange.GetRecords("BTC_USDT") if not records or len(records) < 20: Sleep(5000) continue # Simple moving average strategy ma5 = TA.MA(records, 5) ma20 = TA.MA(records, 20) signal = "HOLD" if ma5[-1] > ma20[-1] and ma5[-2] <= ma20[-2]: signal = "BUY" elif ma5[-1] < ma20[-1] and ma5[-2] >= ma20[-2]: signal = "SELL" # Broadcast trading signal signalData = { "timestamp": time.time() * 1000, "symbol": "BTC_USDT", "signal": signal, "price": records[-1]["Close"], "ma5": ma5[-1], "ma20": ma20[-1] } SetChannelData(signalData) LogStatus("Main Strategy - Signal Broadcast\n" + "Signal: {}\n".format(signal) + "Price: ${:.2f}\n".format(signalData["price"]) + "MA5: {:.2f}\n".format(signalData["ma5"]) + "MA20: {:.2f}".format(signalData["ma20"])) Sleep(60000)c++ -
Practical Application Scenarios
Scenario 1: Master-Slave Strategy Collaborative Trading
Slave Strategy (Signal Reception and Execution Side)
javascriptfunction main() { var masterRobotId = "632799" // Master strategy live trading ID var lastSignal = null Log("Follower strategy started, subscribing to main strategy:", masterRobotId) while(true) { // Get signal from master strategy var signalData = GetChannelData(masterRobotId) if (signalData === null) { LogStatus("Waiting for main strategy signal...") Sleep(5000) continue } // Check for new signal if (lastSignal !== signalData.signal) { Log("Received new signal:", signalData.signal, "Price:", signalData.price) // Execute trade if (signalData.signal === "BUY") { var ticker = exchange.GetTicker(signalData.symbol) if (ticker) { exchange.Buy(ticker.Last, 0.01) Log("Executing buy, Price:", ticker.Last) } } else if (signalData.signal === "SELL") { var ticker = exchange.GetTicker(signalData.symbol) if (ticker) { exchange.Sell(ticker.Last, 0.01) Log("Executing sell, Price:", ticker.Last) } } lastSignal = signalData.signal } LogStatus("Follower Strategy - Following Main Strategy\n" + "Current Signal: " + signalData.signal + "\n" + "Signal Price: $" + signalData.price.toFixed(2) + "\n" + "Signal Time: " + _D(signalData.timestamp)) Sleep(5000) } }pythondef main(): masterRobotId = "632799" # Master strategy live trading ID lastSignal = None Log("Follower strategy started, subscribing to main strategy:", masterRobotId) while True: # Get signal from master strategy signalData = GetChannelData(masterRobotId) if signalData is None: LogStatus("Waiting for main strategy signal...") Sleep(5000) continue # Check for new signal if lastSignal != signalData["signal"]: Log("Received new signal:", signalData["signal"], "Price:", signalData["price"]) # Execute trade if signalData["signal"] == "BUY": ticker = exchange.GetTicker(signalData["symbol"]) if ticker: exchange.Buy(ticker["Last"], 0.01) Log("Executing buy, Price:", ticker["Last"]) elif signalData["signal"] == "SELL": ticker = exchange.GetTicker(signalData["symbol"]) if ticker: exchange.Sell(ticker["Last"], 0.01) Log("Executing sell, Price:", ticker["Last"]) lastSignal = signalData["signal"] LogStatus("Follower Strategy - Following Main Strategy\n" + "Current Signal: {}\n".format(signalData["signal"]) + "Signal Price: ${:.2f}\n".format(signalData["price"]) + "Signal Time: {}".format(_D(signalData["timestamp"]))) Sleep(5000)c++ -
Scenario 2: Multi-Strategy Status Monitoring
Monitoring Strategy
javascriptfunction main() { // List of live trading strategy IDs to monitor var monitorList = ["632799", "632800", "632801"] while(true) { var table = { type: "table", title: "Strategy Running Status Monitor", cols: ["Live ID", "Status", "Last Update", "Trading Pair", "Current Price", "P&L"], rows: [] } for (var i = 0; i < monitorList.length; i++) { var robotId = monitorList[i] var data = GetChannelData(robotId) if (data !== null) { var updateTime = _D(data.timestamp) var timeDiff = Date.now() - data.timestamp var status = timeDiff < 120000 ? "Running" : "Abnormal" table.rows.push([ robotId, status, updateTime, data.symbol || "-", data.lastPrice ? "$" + data.lastPrice.toFixed(2) : "-", data.profit ? data.profit.toFixed(2) + "%" : "-" ]) } else { table.rows.push([ robotId, "Waiting for Data", "-", "-", "-", "-" ]) } } LogStatus("`" + JSON.stringify(table) + "`") Sleep(10000) } }pythondef main(): # List of live trading strategy IDs to monitor monitorList = ["632799", "632800", "632801"] while True: table = { "type": "table", "title": "Strategy Running Status Monitor", "cols": ["Live ID", "Status", "Last Update", "Trading Pair", "Current Price", "P&L"], "rows": [] } for robotId in monitorList: data = GetChannelData(robotId) if data is not None: updateTime = _D(data["timestamp"]) timeDiff = time.time() * 1000 - data["timestamp"] status = "Running" if timeDiff < 120000 else "Abnormal" table["rows"].append([ robotId, status, updateTime, data.get("symbol", "-"), "${:.2f}".format(data["lastPrice"]) if "lastPrice" in data else "-", "{:.2f}%".format(data["profit"]) if "profit" in data else "-" ]) else: table["rows"].append([ robotId, "Waiting for Data", "-", "-", "-", "-" ]) LogStatus("`" + json.dumps(table) + "`") Sleep(10000)c++ -
API Function Documentation
SetChannelData(data)
Function: Publish latest status data on the channel
Parameters:
- data: Data to be published, can be any JSON-serializable data structure
Return Value: None
Features:
-
Non-blocking call
-
Overwrites previous data, does not accumulate history
-
Automatically uses current live trading ID as channel ID
Data Length Limit:
-
Must not exceed 1024 bytes after JSON serialization
-
Recommend transmitting only necessary status information
Detailed Documentation: SetChannelData
GetChannelData(robotId)
Function: Subscribe to channel data of specified live trading instance
Parameters:
- robotId: Live trading ID to subscribe to (string or number)
Return Value:
-
Returns null on first call, retry required
-
Returns latest channel data after successful subscription
Features:
-
Non-blocking call
-
Can subscribe to multiple channels
-
Can subscribe to own channel
Detailed Documentation: GetChannelData
Important Notes
-
First Call Returns null: The
GetChannelData()function returnsnullon first call, which is normal behavior. Wait for data synchronization to complete. Recommend implementing null checks in code. -
Data Overwrite Mechanism: Channel only stores latest status, calling
SetChannelData()overwrites previous data. If historical data preservation is needed, subscribers should record it themselves. -
Non-blocking Characteristics: All channel communication functions are non-blocking and will not affect main strategy execution flow. However, this also means data immediacy cannot be guaranteed.
-
Data Size Limit: Data passed to SetChannelData must not exceed 1024 bytes after JSON serialization. Should only transmit necessary status information such as trading signals, prices, positions and other key data. Avoid transmitting complete candlestick arrays or large amounts of historical data.
-
Live Trading Environment Limitation: Channel communication functionality is primarily designed for live trading environments and may be limited or unavailable in backtesting systems.
-
Live Trading ID Retrieval: Current live trading ID can be obtained through
_G()function, or viewed in platform interface. -
Security Considerations: Channel data may be subscribed to by other authorized live trading instances. Do not transmit sensitive information (such as API keys) through channels.
Best Practices
-
Reasonable Update Frequency: Set data update frequency based on actual needs, avoid overly frequent updates that waste resources.
-
Data Structure Design: Design clear data structures including necessary metadata (such as timestamps, version numbers, etc.) for easier subscriber processing.
-
Error Handling: Subscribers should handle null return values, broadcasters should ensure correct data format.
-
Status Version Control: Include version numbers or update IDs in data to help subscribers determine if there is new data.
-
Monitoring and Alerting: For critical communication links, recommend implementing timeout monitoring and alerting mechanisms.
-
Testing and Validation: Verify channel communication stability and latency in test environment before formal use.
-
Documentation: Document channel data formats and communication protocols for future maintenance and team collaboration.
See Also