Multi-robot market quotes sharing solution
Tags: robot, market, trading, fmzquant
Published: 2024-06-18 09:01:00

When using digital currency quantitative trading robots, when there are multiple robots running on a server, if you visit different exchanges, the issue is not serious at this time, and there will be no API request frequency problem. If you need to have multiple robots running at the same time, and they are all visit the same exchange with the same trading pair quantitative trading strategy. At this time, there will be some issues of API request frequency limitation. So how to solve the problem of multi-robot access interface with the least number of servers?

We can implement a market quotation forwarding robot, and access the exchange interface to obtain market quotations and other data can only be completed by this robot. Other trading strategy robots can request data from this market forwarding robot.

## Quote forwarding robot example
It is only responsible for accessing the exchange market quotation interface to obtain data and provide market quotations to other robots. Written in Python, in the example we only get K-line data and provide sharing, which can be expanded to increase depth data, aggregate market data, etc.
```
import _thread
import threading
import json
import math
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import parse_qs, urlparse

Records = None
lock = threading.RLock()
Counter = {}

def url2Dict(url):
    query = urlparse(url).query  
    params = parse_qs(query)  
    result = {key: params[key][0] for key in params}  
    return result

class Provider(BaseHTTPRequestHandler):
    def do_GET(self):
        global Records, lock, Counter
        try:
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.end_headers()

            dictParam = url2Dict(self.path)
            # Log("The service receives the request, self.path:", self.path, "query parameter:", dictParam)
            lock.acquire()
            # Recording
            if dictParam["robotId"] not in Counter:
                Counter[dictParam["robotId"]] = {"NumberOfRequests" : 0}
            Counter[dictParam["robotId"]]["NumberOfRequests"] += 1
            lock.release()
            
            # Write data response
            self.wfile.write(json.dumps(Records).encode())
        except BaseException as e:
            Log("Provider do_GET error, e:", e)


def createServer(host):
    try:
        server = HTTPServer(host, Provider)
        Log("Starting server, listen at: %s:%s" % host)
        server.serve_forever()
    except BaseException as e:
        Log("createServer error, e:", e)
        raise Exception("stop")

def main():
    global Records, Counter
    LogReset(1)
    try:
        # _thread.start_new_thread(createServer, (("localhost", 9090), ))         # local computer test
        _thread.start_new_thread(createServer, (("0.0.0.0", 9090), ))             # Test on VPS server
        Log("Start service", "#FF0000")
    except BaseException as e:
        Log("Failed to start service!")
        Log("Error message:", e)
        raise Exception("stop")
    while True:
        r = exchange.GetRecords()
        if not r :
            Log("K-line market quotation failed", "#FF0000")
            continue
        else :
            Records = r
        # Counter
        tbl = {
            "type" : "table", 
            "title" : "Statistics", 
            "cols" : ["ID of the robot requesting data", "Number of requests"], 
            "rows" : [], 
        }
        for k in Counter:
            tbl["rows"].append([k, Counter[k]["NumberOfRequests"]])
        LogStatus(_D(), "Data collection!", "\n", "`" + json.dumps(tbl) + "`")
        Sleep(500)
```
## Request data robot strategy code
The robot requesting data is a trading strategy robot, but we use it for testing. We only write the requested data (K-line data) and draw the data. You can write it in JavaScript. In order to draw a picture, you need to check the "Line drawing library". Search and copy this class library in Strategy Square. After copying, you can select it in the template reference column on the strategy editing page.
```
var FuncGetRecords = exchange.GetRecords
exchange.GetRecords = function() {
    // You can fill in the IP address of the device where the "quote forwarding robot" is located xxx.xxx.xxx.xxx
    var ret = HttpQuery("http://xxx.xxx.xxx.xxx:9090?robotId=" + _G())  
    var records = null
    try {
        records = JSON.parse(ret)
    } catch(e) {
        Log(e)
        records = null
    }
    return records 
}

function main(){
    LogReset(1)
    while(1) {
        var records = exchange.GetRecords()
        LogStatus(_D(), "Robot ID:", _G())
        if (!records) {
            Log("Failed to get data!", "#FF0000")
            Sleep(1000)
            continue
        }
        Log(records)
        $.PlotRecords(records, "K")
        Sleep(1000)
    }
}
```
## Actual operation
Start the market forwarding robot

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jxbbjb3nryo1v0tzyh32.png)

Start the test robot, ID: 206353

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/19bkw5q95ngd05hqjwh1.png)

Start the test robot, ID: 206359

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f5f6bfi13a0ggdajjwtb.png)

In this way, three or even N robots can share the K-line data of a certain trading pair.

From: https://www.fmz.com/digest-topic/5938