tupyy / vwap

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

vwap

How to run

Shell

If you have go installed:

make build.vendor
make build run

Docker

make build.docker
make run.docker

Other targets

  • Find information related to the Makefile: make or make help
  • Format code: make check.fmt
  • Format import: make check.imports
  • Code linter : make check.lint
  • Execute TU: make check.test
  • Create container for lint/format: make build.tools

Configuration

The app can be configured by flags or with a configuration file:

./target/run --help
Usage of ./target/run:
  -config string
    	path of the configuration file
  -endpoint string
    	endpoint ws address
  -log_level string
    	log level (default "info")
  -max_data_points int
    	maximum number of data points used to compute the average (default 200)
  -output string
    	path of the output file
  -pairs string
    	comma separated trading pairs

If the configuration file is set, the other flags are ignored. Configuration file:

{
    "log_level": "info",
    "endpoint": "wss://ws-feed.exchange.coinbase.com",
    "trading_pairs": [
        "BTC-USD", "ETH-USD", "ETH-BTC"
    ],
    "max_data_points": 200
}

Design and assumptions

The app has a clean architecture design. It has two layers: transport layer (websocket, output repo module) and usecase. The idea is to decouple the transport layer from usecase to be able to scale up easily if a large number of pair trading are to be computed.

Transport layer

Only one connection is made to ws server although a connection per trading pair can be setup. On each message arrival, the client find the type of the message. Then the message is parsed into a corresponding entity. This process of parsing the type of message and then the whole message was done in order to have a loose coupling of the low level read method readWs and the receive method of the client. When the parsing is done, the entity is written into a channel which is consumed by the usecase. The use of channel between the layers allows the usecase to consume the message at its pace.

Usecase

The usecase has a central component (AvgManager the name could be better I admit) which consume messages from input channel and, for each trading pair, calls the TradingPairAvgCalculator for each ticker of heartbeat message. Each trading pair has his own TradingPairAvgCalculator stored in a map.

The job of TradingPairAvgCalculator is to make sure that the sequence of the ticker is equal or superior of the sequence of the last hearbeat. Internally, TradingPairAvgCalculator has an average calculator.

The math is done in the Calculator.The calculator is very flexible. The maximum number of data points is set as a parameter.

The data points are saved in a LILO stack. The complexity of the is O(1). To achieve O(1), at each insert the sum of products price * volume is computed. If the maximum number of points is reached, the fall off data point is substracted from the sum of products. Therefore, at each insert after the maximum number of data points has been reached, the sum is:

    sum = sum - price_falloff * vol_falloff + price_newpoint * vol_newpoint

Same idea is applied for total volume. Therefore, when average is compute it's just a simple matter of a division.

About


Languages

Language:Go 81.4%Language:Makefile 15.3%Language:Dockerfile 3.3%