This is a WebSocket market template officially developed by FMZ. Welcome all users to copy and use it: https://www.fmz.com/strategy/470349
At present, the FMZ strategy is mainly based on the traditional REST API encapsulation. Each step of API access requires a network connection to be established, and market data is obtained through polling. This method is simple and easy to use, and it is completely sufficient for most needs.
However, the REST protocol has an inherent delay problem. When multiple trading pairs and multiple-exchange strategies are required, the delay problem will be magnified. Although the Go function of the platform can be executed concurrently, the delay problem still exists, which makes it difficult to meet the needs of relatively high-frequency strategy trading. In addition, if there are too many trading pairs and the polling frequency is too fast, it will encounter the access frequency limit of the trading platform.
Currently, the servers of exchanges are also under heavy burden. They all provide a complete WebSocket protocol and recommend it to API users. Compared with the REST protocol, WebSocket provides a persistent two-way connection method, which enables exchanges to push data to the client in real time, avoiding frequent requests and responses, thus greatly reducing latency. Generally speaking, if the delay in accessing the REST API is around 20ms, the delay in pushing data through WebSocket is about 2ms. In addition, the link to the WebSocket protocol is not limited by the platform access frequency, and it is possible to subscribe to dozens of trading pairs at a time.
FMZ Quant Trading platform has supported WebSocket protocol for a long time, and it is relatively convenient to call, but for novice users, it is still too complicated to handle multiple subscriptions, subscribe to multiple exchange tickers, and embed them efficiently and conveniently into the entire strategy process. This public WebSocket real-time ticker data acceleration template solves this problem. It is very easy to use and is fully compatible with the current encapsulated API call. For most of the original REST strategies, you can simply modify them and use them directly to accelerate your strategy.
Key Features:
Note that this strategy uses TypeScript. If you are only familiar with JavaScript, it may look a bit strange. TypeScript introduces a type system and richer language features based on JavaScript. For applications such as quantitative trading that need to handle complex logic, using TypeScript can reduce potential errors and improve the readability and maintainability of the code. Therefore, it is recommended to learn it briefly.
In addition, the strategy uses the asynchronous mechanism of the FMZ platform. The child thread can send messages to the main thread through the __threadPostMessage function. This method is asynchronous and is suitable for notifying the main thread of data updates generated in the child thread. The main thread and the child thread can share data through the __threadGetData and __threadSetData functions. This method allows threads to access and modify shared states. If you want to learn about multithreading, combined with the platform documentation, this strategy is also a good learning example.
The main principle of this strategy is to connect to mainstream digital currency exchanges through WebSocket and receive market data (such as depth information and transaction information) in real time to provide data support for quantitative trading decisions. The specific implementation process is as follows:
1. WebSocket connection settings
The function setupWebsocket
is used to initialize a WebSocket connection and receive market data. It receives a parameter main_exchanges
, indicating the exchange to connect to.
MyDial
function : Create a WebSocket connection, record the connection time, and output the close time when closing the connection.updateSymbols
function : Check regularly whether there are new subscription requests and update the current trading pair list as needed.2. Data processing
The object supports
defines the supported exchanges and their processing function (such as Binance
). The processing function for each exchange is responsible for parsing the received message and extracting the relevant data.
processMsg
function : Process messages from exchanges, identify different types of data (such as depth updates, transactions, etc.), and format them into a unified event object.3. Subscription data At each connection, the system will subscribe to the relevant market data channels based on the current trading pair.
getFunction
function : Get the corresponding processing function according to the exchange name.this.wssPublic
function : Initialize the WebSocket connection and start receiving data.4. Thread management Start a thread for each exchange, receive data in real-time and process the data through callback functions.
threadMarket
function : Receive data in a child thread, parse and store the latest depth and transaction information.5. Rewrite the data acquisition method Rewrite the methods for obtaining depth and trading information for each exchange, giving priority to returning data that is updated in real-time.
$.setupWebsocket()
to initialize the WebSocket connection of the target exchange.GetDepth()
and GetTrades()
functions, the market depth and transaction records are automatically returned using WebSocket real-time data.If the EventLoop() function is added to the strategy, it will be changed to a trigger mechanism. When there is wss data update, it will automatically obtain it immediately, and wait if there is no latest data. It is equivalent to an intelligent Sleep function. Of course, you can also use Sleep directly.
function main() {
$.setupWebsocket()
while (true) {
exchanges.map(e=>{
Log(e.GetName(), e.GetDepth())
Log(e.GetName(), e.GetTrades())
})
EventLoop(100) // trigger by websocket
}
}
Refer to my previous multi-currency trading strategy guide: https://www.fmz.com/bbs-topic/10508 , which can be modified easily to support WebSocket:
function MakeOrder() {
for (let i in Info.trade_symbols) {
let symbol = Info.trade_symbols[i];
let buy_price = exchange.GetDepth(symbol + '_USDT').Asks[0].Price;
let buy_amount = 50 / buy_price;
if (Info.position[symbol].value < 2000){
Trade(symbol, "buy", buy_price, buy_amount, symbol);
}
}
}
function OnTick() {
try {
UpdatePosition();
MakeOrder();
UpdateStatus();
} catch (error) {
Log("loop error: " + error);
}
}
function main() {
$.setupWebsocket()
InitInfo();
while (true) {
let loop_start_time = Date.now();
if (Date.now() - Info.time.last_loop_time > Info.interval * 1000) {
OnTick();
Info.time.last_loop_time = Date.now();
Info.time.loop_delay = Date.now() - loop_start_time;
}
Sleep(5);
}
}