Teach you to implement a market quotes collector
Tags: market, trading, cryptocurrency, fmzquant
Published: 2024-06-13 05:28:33

The support of market quotes data is indispensable when researching, designing and backtest trading strategies. It is not realistic to collect all the data from every market, after all, the amount of data is too large. For the digital currency market, FMZ platform supports limited backtest data for exchanges and trading pairs. If you want to backtest some exchanges and trading pairs that temporarily wasn't supported by FMZ platform, you can use a custom data source for backtest, but this premise requires that you have data. Therefore, there is an urgent need for a market quotes collection program, which can be persisted and best obtained in real time.

In this way, we can solve several needs, such as:

- Multiple robots can be provided with data sources, which can ease the frequency of each robot's access to the exchange interface.
- You can get K-line data with a sufficient number of K-line BARs when the robot starts, and you no longer have to worry about the insufficient number of K-line BARs when the robot starts.
- It can collect market data of rare currencies and provide a custom data source for the FMZ platform backtest system.
and many more..

We plan to use python to achieve this, why? Because it's very convenient

## Ready
- Python's pymongo library
Because you need to use database for persistent storage. The database selection uses MongoDB and the Python language is used to write the collection program, so the driver library of this database is required.
Just install pymongo on Python.

- Install MongoDB on the hosting device
For example: MacOS installs MongoDB, also same as windows system installs MongoDB. There are many tutorials online. Take the installation of MacOS system as an example:

- Download
Download link: https://www.mongodb.com/download-center?jmp=nav#community

- Unzip
After downloading, unzip to the directory: /usr/local

- Configure environment variables
Terminal input: open -e .bash_profile, after opening the file, write: exportPATH=${PATH}:/usr/local/MongoDB/bin
After saving, in the terminal, uses source .bash_profile to make the changes take effect.

- Manually configure the database file directory and log directory
Create the corresponding folder in the directory /usr/local/data/db.
Create the corresponding folder in the directory /usr/local/data/logs.

Edit the configuration file mongo.conf:
```
#bind_ip_all = true # Any computer can connect
bind_ip = 127.0.0.1 # Local computer can access
port = 27017 # The instance runs on port 27017 (default)
dbpath = /usr/local/data/db # data folder storage address (db need to be created in advance)
logpath = /usr/local/data/logs/mongodb.log # log file address
logappend = false # whether to add or rewrite the log file at startup
fork = false # Whether to run in the background
auth = false # Enable user verification
```

- Run MongoDB service
command:
```
./mongod -f mongo.conf
```

- Stop MongoDB service
```
use admin;
db.shutdownServer();
```
## Implement the collector program
The collector operates as a Python robot strategy on FMZ platform. I just implemented a simple example to show the ideas of this article.

Collector program code:
```
import pymongo
import json

def main():
    Log("Test data collection")
    
    # Connect to the database service
    myDBClient = pymongo.MongoClient("mongodb://localhost:27017")   # mongodb://127.0.0.1:27017
    # Create a database
    huobi_DB = myDBClient["huobi"]
    
    # Print the current database table
    collist = huobi_DB.list_collection_names()
    Log("collist:", collist)
    
    # Check if the table is deleted
    arrDropNames = json.loads(dropNames)
    if isinstance(arrDropNames, list):
        for i in range(len(arrDropNames)):
            dropName = arrDropNames[i]
            if isinstance(dropName, str):
                if not dropName in collist:
                    continue
                tab = huobi_DB[dropName]
                Log("dropName:", dropName, "delete:", dropName)
                ret = tab.drop()
                collist = huobi_DB.list_collection_names()
                if dropName in collist:
                    Log(dropName, "failed to delete")
                else :
                    Log(dropName, "successfully deleted")
    
    # Create the records table
    huobi_DB_Records = huobi_DB["records"]
    
    # Request data
    preBarTime = 0
    index = 1
    while True:
        r = _C(exchange.GetRecords)
        if len(r) < 2:
            Sleep(1000)
            continue
        if preBarTime == 0:
            # Write all BAR data for the first time
            for i in range(len(r) - 1):
                # Write one by one
                bar = r[i]
                huobi_DB_Records.insert_one({"index": index, "High": bar["High"], "Low": bar["Low"], "Open": bar["Open"], "Close": bar["Close"], "Time": bar["Time"], "Volume": bar["Volume"]})                
                index += 1
            preBarTime = r[-1]["Time"]
        elif preBarTime != r[-1]["Time"]:
            bar = r[-2]
            huobi_DB_Records.insert_one({"index": index, "High": bar["High"], "Low": bar["Low"], "Open": bar["Open"], "Close": bar["Close"], "Time": bar["Time"], "Volume": bar["Volume"]})
            index += 1
            preBarTime = r[-1]["Time"]
        LogStatus(_D(), "preBarTime:", preBarTime, "_D(preBarTime):", _D(preBarTime/1000), "index:", index)
        Sleep(10000)
```
Full strategy address: https://www.fmz.com/strategy/199120

## Usage data
Create a strategy robot that uses data.
Note: You need to check the "python PlotLine Template", if you don't have it, you can copy one from the strategy square to your strategy library.

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

Here is the address: https://www.fmz.com/strategy/39066
```
import pymongo
import json

def main():
    Log("Test using database data")
    
    # Connect to the database service
    myDBClient = pymongo.MongoClient("mongodb://localhost:27017")   # mongodb://127.0.0.1:27017
    # Create a database
    huobi_DB = myDBClient["huobi"]
    
    # Print the current database table
    collist = huobi_DB.list_collection_names()
    Log("collist:", collist)
    
    # Query data printing
    huobi_DB_Records = huobi_DB["records"]
    
    while True:
        arrRecords = []
        for x in huobi_DB_Records.find():
            bar = {
                "High": x["High"], 
                "Low": x["Low"], 
                "Close": x["Close"], 
                "Open": x["Open"], 
                "Time": x["Time"], 
                "Volume": x["Volume"]
            }
            arrRecords.append(bar)
        
        # Use the line drawing library to draw the obtained K-line data
        ext.PlotRecords(arrRecords, "K")
        LogStatus(_D(), "records length:", len(arrRecords))
        Sleep(10000)
```
It can be seen that the strategy robot code that uses the data does not access any exchange interface. The data is obtained by accessing the database. The market collector program does not record the current BAR data. It collects the K-line BAR in the completed state. If the current BAR real-time data is needed, it can be modified slightly.

The current example code is just for demonstration. When accessing the data records in the table in the database, all are obtained. In this way, as the time for collecting data increases, more and more data is collected. All queries will affect performance to a certain extent, and can be designed. Only data that is newer than the current data is queried and added to the current data.

## Run
Running docker program

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

On the device where the docker is located, run the MongoDB database service

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

The collector runs to collect the BTC_USDT trading pairs of FMZ Platform WexApp simulation exchange marekt quotes:
WexApp Address: https://wex.app/trade?currency=BTC_USDT

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

Robot A using database data:

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

Robot B using database data:

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

WexApp page:

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

As you can see in the figure, robots with different IDs share K-line data using one data source.

## Collect K-line data of any period
Relying on the powerful functions of FMZ platform, we can easily collect K-line data at any cycle.
For example, I want to collect a 3-minute K-line, what if the exchange does not have a 3-minute K-line? It does not matter, it can be easily achieved.

We modify the configuration of the collector robot, the K line period is set to 3 minutes, and FMZ platform will automatically synthesize a 3 minute K line to the collector program.

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

We use the parameter to delete the name of the table, setting: ["records"] delete the 1 minute K-line data table collected before. Prepare to collect 3-minute K-line data.

Start the collector program, and then re-start the strategy robot using the data.

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

You can see the K-line chart drawn, the interval between BARs is 3 minutes, and each BAR is a K-line bar with a 3-minute period.

In the next issue, we will try to implement the requirements of custom data sources.

Thanks for reading!

From: https://blog.mathquant.com/2020/05/30/teach-you-to-implement-a-market-quotes-collector.html