mass rename
Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
parent
70b3c3f202
commit
0fed0c544c
|
@ -1,7 +1,7 @@
|
||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
- package-ecosystem: npm
|
- package-ecosystem: npm
|
||||||
directory: "/mango-service-v3"
|
directory: "/mango-service-v4"
|
||||||
schedule:
|
schedule:
|
||||||
interval: daily
|
interval: daily
|
||||||
time: "01:00"
|
time: "01:00"
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
.idea
|
.idea
|
||||||
__pycache__/
|
__pycache__/
|
||||||
mango-service-v3/node_modules
|
mango-service-v4/node_modules
|
||||||
mango-service-v3/dist
|
mango-service-v4/dist
|
||||||
mango-service-v3/run-dev-server.sh
|
mango-service-v4/run-dev-server.sh
|
||||||
mango-service-v3/run-dev-server-devnet.sh
|
mango-service-v4/run-dev-server-devnet.sh
|
||||||
mango-service-v3/run-build-and-publish-docker-image.sh
|
mango-service-v4/run-build-and-publish-docker-image.sh
|
||||||
mango-service-v3/run-build-and-test-docker-locally.sh
|
mango-service-v4/run-build-and-test-docker-locally.sh
|
||||||
mango-service-v3/run-update-api-docs.sh
|
mango-service-v4/run-update-api-docs.sh
|
||||||
py/.venv
|
py/.venv
|
||||||
py/.idea
|
py/.idea
|
||||||
py/mango_service_v3_py/__pycache__/
|
py/mango_service_v4_py/__pycache__/
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[submodule "mango-bowl"]
|
|
||||||
path = mango-bowl
|
|
||||||
url = https://github.com/tardis-dev/mango-bowl
|
|
19
README.md
19
README.md
|
@ -1,31 +1,36 @@
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
REST and WEBSOCKET API Services for mango markets version 3, and some simple clients and examples. Aimed to follow spec as close as possible to popular exchanges like ftx, etc. Current motivation is to enable traders to bring their existing tools to mango markets.
|
REST and WEBSOCKET API Services for mango markets version 3, and some simple clients and examples. Aimed to follow spec as close as possible to popular exchanges like ftx, etc. Current motivation is to enable traders to bring their existing tools to mango markets.
|
||||||
|
|
||||||
# Note
|
# Note
|
||||||
|
|
||||||
REST Service requires the user to run a local copy with his/her own private key. An alternative approach which is known and was not taken is to prepare solana transactions in a centrally hosted REST API Service and send them back to the client for signing using their wallet. The advantages of this would be that we could have a centrally hosted service, and would save local hosting, the disadvantages of this would be complicating the REST clients users want to use with solana specific signing code and would need us to ship and maintain clients for various programming languages. Also such a centrally hosted service would then need authorization, authentication, rate limiting, etc. to prevent abuse of the configured RPC node, which so far is not the aim of this project.
|
REST Service requires the user to run a local copy with his/her own private key. An alternative approach which is known and was not taken is to prepare solana transactions in a centrally hosted REST API Service and send them back to the client for signing using their wallet. The advantages of this would be that we could have a centrally hosted service, and would save local hosting, the disadvantages of this would be complicating the REST clients users want to use with solana specific signing code and would need us to ship and maintain clients for various programming languages. Also such a centrally hosted service would then need authorization, authentication, rate limiting, etc. to prevent abuse of the configured RPC node, which so far is not the aim of this project.
|
||||||
|
|
||||||
WEBSOCKET API currently streams L1, and L2 level orderbook data.
|
WEBSOCKET API currently streams L1, and L2 level orderbook data.
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
See https://microwavedcola1.github.io/mango-service-v3/#tag/default
|
|
||||||
|
See https://microwavedcola1.github.io/mango-service-v4/#tag/default
|
||||||
|
|
||||||
Directory structure
|
Directory structure
|
||||||
|
|
||||||
```
|
```
|
||||||
.
|
.
|
||||||
├── README.md
|
├── README.md
|
||||||
├── mango-service-v3 - REST API Service for mango markets version 3
|
├── mango-service-v4 - REST API Service for mango markets version 3
|
||||||
├── mango-bowl - WEBSOCKET API Service for L1, L2 orderbook data for mango markets version 3
|
|
||||||
└── py - python3 client for above REST API Service
|
└── py - python3 client for above REST API Service
|
||||||
```
|
```
|
||||||
|
|
||||||
# How to run
|
# How to run
|
||||||
* `docker-compose up` starts the REST API Service and the WEBSOCKET API Service, and a ngninx reverse proxy
|
|
||||||
* The REST API is then available e.g. `curl http://localhost/api/wallet/balances`
|
|
||||||
* the WEBSOCKET API is then available e.g.`wscat --connect ws://localhost/ws` (note by default the websocket program when run in isolation is available at `ws://localhost/v1/ws` )
|
|
||||||
|
|
||||||
|
- `docker-compose up` starts the REST API Service and the WEBSOCKET API Service, and a ngninx reverse proxy
|
||||||
|
- The REST API is then available e.g. `curl http://localhost/api/wallet/balances`
|
||||||
|
- the WEBSOCKET API is then available e.g.`wscat --connect ws://localhost/ws` (note by default the websocket program when run in isolation is available at `ws://localhost/v1/ws` )
|
||||||
|
|
||||||
# Todos
|
# Todos
|
||||||
|
|
||||||
losely sorted in order of importance/priority
|
losely sorted in order of importance/priority
|
||||||
|
|
||||||
- rpc node related issues
|
- rpc node related issues
|
||||||
- ensure that order has been placed or definitely not placed on the server side
|
- ensure that order has been placed or definitely not placed on the server side
|
||||||
- some off chain services are used, these might use other nodes, mixing data from various nodes, might be problematic, what if one node is behind?
|
- some off chain services are used, these might use other nodes, mixing data from various nodes, might be problematic, what if one node is behind?
|
||||||
|
@ -38,7 +43,9 @@ losely sorted in order of importance/priority
|
||||||
- add pre commit tools e.g. husky/pre-commit for code formatting and linting
|
- add pre commit tools e.g. husky/pre-commit for code formatting and linting
|
||||||
|
|
||||||
# Feedback
|
# Feedback
|
||||||
|
|
||||||
so far from beta tasters, from twitter, discord, etc.
|
so far from beta tasters, from twitter, discord, etc.
|
||||||
|
|
||||||
- auto create mango account if none exists
|
- auto create mango account if none exists
|
||||||
- deposit collateral using cross-chain bridges
|
- deposit collateral using cross-chain bridges
|
||||||
- new endpoints
|
- new endpoints
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
version: "3.9"
|
version: "3.9"
|
||||||
services:
|
services:
|
||||||
mango-service-v3:
|
mango-service-v4:
|
||||||
build: mango-service-v3
|
build: mango-service-v4
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -11,16 +11,9 @@ services:
|
||||||
- GROUP_NAME=mainnet.1
|
- GROUP_NAME=mainnet.1
|
||||||
- CLUSTER_URL=${CLUSTER_URL} # configure custom RPC node
|
- CLUSTER_URL=${CLUSTER_URL} # configure custom RPC node
|
||||||
- PRIVATE_KEY_PATH=/root/.config/solana/id.json # configure path to private keypair here
|
- PRIVATE_KEY_PATH=/root/.config/solana/id.json # configure path to private keypair here
|
||||||
mango-bowl:
|
|
||||||
build: "mango-bowl"
|
|
||||||
ports:
|
|
||||||
- "8000:8000"
|
|
||||||
environment:
|
|
||||||
- MB_PORT=8000
|
|
||||||
- MB_ENDPOINT=${CLUSTER_URL} # configure custom RPC node
|
|
||||||
reverse-proxy:
|
reverse-proxy:
|
||||||
build: .
|
build: .
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf/:/etc/nginx/nginx.conf # custom config which unifies mango-service-v3 and mango-bowl
|
- ./nginx.conf/:/etc/nginx/nginx.conf # custom config which unifies mango-service-v4
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 7865688be6b261adc7ffb8f67e579e7efd5ad74b
|
|
|
@ -11,4 +11,4 @@ RUN yarn build
|
||||||
|
|
||||||
ENV PORT=3000
|
ENV PORT=3000
|
||||||
|
|
||||||
CMD ["pm2-docker", "start", "dist/server.js", "-i", "2", "-n", "mango-service-v3", "--max-memory-restart", "200M"]
|
CMD ["pm2-docker", "start", "dist/server.js", "-i", "2", "-n", "mango-service-4", "--max-memory-restart", "200M"]
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
A REST API server on top of mango markets v3, written in typescript + expressjs + using mango client and some other off chain REST services.
|
A REST API server on top of mango markets v4, written in typescript + expressjs + using mango client and some other off chain REST services.
|
||||||
|
|
||||||
# Environment variables
|
# Environment variables
|
||||||
All environment variables are optional.
|
All environment variables are optional.
|
||||||
|
@ -14,9 +14,9 @@ All environment variables are optional.
|
||||||
* `yarn ts-node ./src/server.ts` or if you have `nodemon` installed then, `nodemon ./src/server.ts`
|
* `yarn ts-node ./src/server.ts` or if you have `nodemon` installed then, `nodemon ./src/server.ts`
|
||||||
|
|
||||||
# How to run using docker
|
# How to run using docker
|
||||||
* `docker pull microwavedcola/mango-service-v3`
|
* `docker pull microwavedcola/mango-service-v4`
|
||||||
* `docker run -p 3000:3000 -v ~/.config:/root/.config microwavedcola/mango-service-v3`, assumes private key to be present at ~/.config/solana/id.json
|
* `docker run -p 3000:3000 -v ~/.config:/root/.config microwavedcola/mango-service-v4`, assumes private key to be present at ~/.config/solana/id.json
|
||||||
|
|
||||||
# How to test
|
# How to test
|
||||||
* via postman, see `service-v3.postman_collection.json`
|
* via postman, see `service-v4.postman_collection.json`
|
||||||
* python client, see https://github.com/microwavedcola1/mango-v3-service/blob/master/py/README.md
|
* python client, see https://github.com/microwavedcola1/mango-v4-service/blob/master/py/README.md
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "mango-service-v3",
|
"name": "mango-service-v4",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "REST API for trading against mango markets",
|
"description": "REST API for trading against mango markets",
|
||||||
"main": "./src/server.ts",
|
"main": "./src/server.ts",
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"info": {
|
"info": {
|
||||||
"_postman_id": "6400c7b4-eaa6-4a86-b7df-19857192378e",
|
"_postman_id": "6400c7b4-eaa6-4a86-b7df-19857192378e",
|
||||||
"name": "service-v3",
|
"name": "service-4",
|
||||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||||
},
|
},
|
||||||
"item": [
|
"item": [
|
|
@ -1,6 +1,6 @@
|
||||||
openapi: 3.0.0
|
openapi: 3.0.0
|
||||||
info:
|
info:
|
||||||
title: service-v3
|
title: service-v4
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
servers:
|
servers:
|
||||||
- url: http://{{baseurl}}
|
- url: http://{{baseurl}}
|
|
@ -406,7 +406,7 @@ class MangoSimpleClient {
|
||||||
perpMarketConfig.baseDecimals,
|
perpMarketConfig.baseDecimals,
|
||||||
perpMarketConfig.quoteDecimals
|
perpMarketConfig.quoteDecimals
|
||||||
);
|
);
|
||||||
// TODO: this is a workaround, mango-v3 has a assertion for price>0 for all order types
|
// TODO: this is a workaround, mango-v4 has a assertion for price>0 for all order types
|
||||||
// this will be removed soon hopefully
|
// this will be removed soon hopefully
|
||||||
price = orderType !== "market" ? price : 1;
|
price = orderType !== "market" ? price : 1;
|
||||||
return await this.client.placePerpOrder(
|
return await this.client.placePerpOrder(
|
|
@ -78,7 +78,7 @@ class WalletController implements Controller {
|
||||||
mangoGroup.loadRootBanks(this.mangoSimpleClient.connection),
|
mangoGroup.loadRootBanks(this.mangoSimpleClient.connection),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
////// copy pasta block from mango-ui-v3
|
////// copy pasta block from mango-ui-v4
|
||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
const balances: Balances[][] = new Array();
|
const balances: Balances[][] = new Array();
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ class WalletController implements Controller {
|
||||||
const tokenIndex = mangoGroup.getTokenIndex(token.mintKey);
|
const tokenIndex = mangoGroup.getTokenIndex(token.mintKey);
|
||||||
const value = net.mul(mangoGroup.getPrice(tokenIndex, mangoCache));
|
const value = net.mul(mangoGroup.getPrice(tokenIndex, mangoCache));
|
||||||
/* tslint:enable */
|
/* tslint:enable */
|
||||||
////// end of copy pasta block from mango-ui-v3
|
////// end of copy pasta block from mango-ui-v4
|
||||||
// append balances for base symbols
|
// append balances for base symbols
|
||||||
const balanceDtos = baseBalances.map((baseBalance) => {
|
const balanceDtos = baseBalances.map((baseBalance) => {
|
||||||
return {
|
return {
|
|
@ -13,11 +13,7 @@ http {
|
||||||
}
|
}
|
||||||
|
|
||||||
upstream rest-api {
|
upstream rest-api {
|
||||||
server mango-service-v3:3000;
|
server mango-service-v4:3000;
|
||||||
}
|
|
||||||
|
|
||||||
upstream ws-api {
|
|
||||||
server mango-bowl:8000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
|
||||||
A python3 client with some examples for the mango markets v3 REST Service
|
A python3 client with some examples for the mango markets v4 REST Service
|
||||||
|
|
||||||
# Pre-requisites
|
# Pre-requisites
|
||||||
* you have [poetry](https://python-poetry.org/docs/#installation) installed
|
* you have [poetry](https://python-poetry.org/docs/#installation) installed
|
||||||
* you have the REST API service from `../mango-service-v3 running` locally
|
* you have the REST API service from `../mango-service-v4 running` locally
|
||||||
|
|
||||||
|
|
||||||
# How to test examples while developing
|
# How to test examples while developing
|
||||||
|
|
|
@ -1,41 +1,41 @@
|
||||||
from mango_service_v3_py.api import MangoServiceV3Client
|
from mango_service_v4_py.api import MangoServiceV4Client
|
||||||
from mango_service_v3_py.dtos import PlaceOrder
|
from mango_service_v4_py.dtos import PlaceOrder
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
mango_service_v3_client = MangoServiceV3Client()
|
mango_service_v4_client = MangoServiceV4Client()
|
||||||
|
|
||||||
for position in mango_service_v3_client.get_open_positions():
|
for position in mango_service_v4_client.get_open_positions():
|
||||||
print(position.json(indent=4, sort_keys=True))
|
print(position.json(indent=4, sort_keys=True))
|
||||||
|
|
||||||
for balance in mango_service_v3_client.get_balances():
|
for balance in mango_service_v4_client.get_balances():
|
||||||
print(balance.json(indent=4, sort_keys=True))
|
print(balance.json(indent=4, sort_keys=True))
|
||||||
|
|
||||||
for market in mango_service_v3_client.get_markets():
|
for market in mango_service_v4_client.get_markets():
|
||||||
print(market.json(indent=4, sort_keys=True))
|
print(market.json(indent=4, sort_keys=True))
|
||||||
print(
|
print(
|
||||||
mango_service_v3_client.get_market_by_market_name("BTC-PERP").json(
|
mango_service_v4_client.get_market_by_market_name("BTC-PERP").json(
|
||||||
indent=4, sort_keys=True
|
indent=4, sort_keys=True
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
for order in mango_service_v3_client.get_orderbook("BTC-PERP"):
|
for order in mango_service_v4_client.get_orderbook("BTC-PERP"):
|
||||||
print(order.json(indent=4, sort_keys=True))
|
print(order.json(indent=4, sort_keys=True))
|
||||||
|
|
||||||
for trade in mango_service_v3_client.get_trades("BTC-PERP"):
|
for trade in mango_service_v4_client.get_trades("BTC-PERP"):
|
||||||
print(trade.json(indent=4, sort_keys=True))
|
print(trade.json(indent=4, sort_keys=True))
|
||||||
|
|
||||||
for candle in mango_service_v3_client.get_candles(
|
for candle in mango_service_v4_client.get_candles(
|
||||||
"BTC-PERP", 60, 1625922900, 1631214960
|
"BTC-PERP", 60, 1625922900, 1631214960
|
||||||
):
|
):
|
||||||
print(candle.json(indent=4, sort_keys=True))
|
print(candle.json(indent=4, sort_keys=True))
|
||||||
|
|
||||||
for order in mango_service_v3_client.get_orders():
|
for order in mango_service_v4_client.get_orders():
|
||||||
print(order.json(indent=4, sort_keys=True))
|
print(order.json(indent=4, sort_keys=True))
|
||||||
for order in mango_service_v3_client.get_orders_by_market_name("BTC-PERP"):
|
for order in mango_service_v4_client.get_orders_by_market_name("BTC-PERP"):
|
||||||
print(order.json(indent=4, sort_keys=True))
|
print(order.json(indent=4, sort_keys=True))
|
||||||
|
|
||||||
mango_service_v3_client.place_order(
|
mango_service_v4_client.place_order(
|
||||||
PlaceOrder(
|
PlaceOrder(
|
||||||
market="BTC-PERP",
|
market="BTC-PERP",
|
||||||
side="buy",
|
side="buy",
|
||||||
|
@ -48,14 +48,14 @@ if __name__ == "__main__":
|
||||||
client_id=123,
|
client_id=123,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
for order in mango_service_v3_client.get_orders():
|
for order in mango_service_v4_client.get_orders():
|
||||||
print(order.json(indent=4, sort_keys=True))
|
print(order.json(indent=4, sort_keys=True))
|
||||||
|
|
||||||
mango_service_v3_client.cancel_order_by_client_id("123")
|
mango_service_v4_client.cancel_order_by_client_id("123")
|
||||||
for order in mango_service_v3_client.get_orders():
|
for order in mango_service_v4_client.get_orders():
|
||||||
print(order.json(indent=4, sort_keys=True))
|
print(order.json(indent=4, sort_keys=True))
|
||||||
|
|
||||||
mango_service_v3_client.place_order(
|
mango_service_v4_client.place_order(
|
||||||
PlaceOrder(
|
PlaceOrder(
|
||||||
market="BTC/USDC",
|
market="BTC/USDC",
|
||||||
side="buy",
|
side="buy",
|
||||||
|
@ -68,13 +68,13 @@ if __name__ == "__main__":
|
||||||
client_id=123,
|
client_id=123,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
for order in mango_service_v3_client.get_orders():
|
for order in mango_service_v4_client.get_orders():
|
||||||
print(order.json(indent=4, sort_keys=True))
|
print(order.json(indent=4, sort_keys=True))
|
||||||
|
|
||||||
mango_service_v3_client.cancel_order_by_client_id("123")
|
mango_service_v4_client.cancel_order_by_client_id("123")
|
||||||
for order in mango_service_v3_client.get_orders():
|
for order in mango_service_v4_client.get_orders():
|
||||||
print(order.json(indent=4, sort_keys=True))
|
print(order.json(indent=4, sort_keys=True))
|
||||||
|
|
||||||
mango_service_v3_client.cancel_all_orders()
|
mango_service_v4_client.cancel_all_orders()
|
||||||
for order in mango_service_v3_client.get_orders():
|
for order in mango_service_v4_client.get_orders():
|
||||||
print(order.json(indent=4, sort_keys=True))
|
print(order.json(indent=4, sort_keys=True))
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
from mango_service_v3_py.api import MangoServiceV3Client
|
from mango_service_v4_py.api import MangoServiceV4Client
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
mango_service_v3_client = MangoServiceV3Client()
|
mango_service_v4_client = MangoServiceV4Client()
|
||||||
|
|
||||||
print("orders before cancelling")
|
print("orders before cancelling")
|
||||||
for order in mango_service_v3_client.get_orders():
|
for order in mango_service_v4_client.get_orders():
|
||||||
print(order.json(indent=4, sort_keys=True))
|
print(order.json(indent=4, sort_keys=True))
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
mango_service_v3_client.cancel_all_orders()
|
mango_service_v4_client.cancel_all_orders()
|
||||||
print("orders after cancelling")
|
print("orders after cancelling")
|
||||||
for order in mango_service_v3_client.get_orders():
|
for order in mango_service_v4_client.get_orders():
|
||||||
print(order.json(indent=4, sort_keys=True))
|
print(order.json(indent=4, sort_keys=True))
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from mango_service_v3_py.api import MangoServiceV3Client
|
from mango_service_v4_py.api import MangoServiceV4Client
|
||||||
from mango_service_v3_py.dtos import PlaceOrder
|
from mango_service_v4_py.dtos import PlaceOrder
|
||||||
|
|
||||||
MARKET = "BTC-PERP"
|
MARKET = "BTC-PERP"
|
||||||
|
|
||||||
|
@ -13,17 +13,17 @@ def fibonacci_of(n):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
mango_service_v3_client = MangoServiceV3Client()
|
mango_service_v4_client = MangoServiceV4Client()
|
||||||
|
|
||||||
market = mango_service_v3_client.get_market_by_market_name("BTC-PERP")[0]
|
market = mango_service_v4_client.get_market_by_market_name("BTC-PERP")[0]
|
||||||
print(f"latest btc-perp price is {market.last}")
|
print(f"latest btc-perp price is {market.last}")
|
||||||
|
|
||||||
mango_service_v3_client.cancel_all_orders()
|
mango_service_v4_client.cancel_all_orders()
|
||||||
|
|
||||||
balances = mango_service_v3_client.get_balances()
|
balances = mango_service_v4_client.get_balances()
|
||||||
total_usd_balance = sum([balance.usd_value for balance in balances])
|
total_usd_balance = sum([balance.usd_value for balance in balances])
|
||||||
|
|
||||||
market = mango_service_v3_client.get_market_by_market_name(MARKET)[0]
|
market = mango_service_v4_client.get_market_by_market_name(MARKET)[0]
|
||||||
|
|
||||||
lowest = 25
|
lowest = 25
|
||||||
fibs = [fib for fib in [fibonacci_of(n) for n in range(10)] if fib < lowest][1:]
|
fibs = [fib for fib in [fibonacci_of(n) for n in range(10)] if fib < lowest][1:]
|
||||||
|
@ -31,14 +31,14 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
for i, fib in enumerate(fibs):
|
for i, fib in enumerate(fibs):
|
||||||
price = market.last * ((100 - fibs[-1] + fib) / 100)
|
price = market.last * ((100 - fibs[-1] + fib) / 100)
|
||||||
price = mango_service_v3_client.to_nearest(price, market.price_increment)
|
price = mango_service_v4_client.to_nearest(price, market.price_increment)
|
||||||
|
|
||||||
size = (total_usd_balance / market.price) * (fibs[len(fibs) - 1 - i] / fibs_sum)
|
size = (total_usd_balance / market.price) * (fibs[len(fibs) - 1 - i] / fibs_sum)
|
||||||
size = mango_service_v3_client.to_nearest(size, market.size_increment)
|
size = mango_service_v4_client.to_nearest(size, market.size_increment)
|
||||||
if size < market.size_increment:
|
if size < market.size_increment:
|
||||||
continue
|
continue
|
||||||
print(f"setting order, price: {price}, size: {size}, value: {price * size}")
|
print(f"setting order, price: {price}, size: {size}, value: {price * size}")
|
||||||
mango_service_v3_client.place_order(
|
mango_service_v4_client.place_order(
|
||||||
PlaceOrder(
|
PlaceOrder(
|
||||||
market=MARKET,
|
market=MARKET,
|
||||||
side="buy",
|
side="buy",
|
||||||
|
@ -51,5 +51,5 @@ if __name__ == "__main__":
|
||||||
client_id=int(time.time()),
|
client_id=int(time.time()),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
for order in mango_service_v3_client.get_orders():
|
for order in mango_service_v4_client.get_orders():
|
||||||
print(f"set order at, price: {order.price}, size: {order.size}")
|
print(f"set order at, price: {order.price}, size: {order.size}")
|
||||||
|
|
|
@ -9,8 +9,8 @@ from os.path import getmtime
|
||||||
|
|
||||||
from tenacity import retry, wait_fixed, stop_after_delay, stop_after_attempt
|
from tenacity import retry, wait_fixed, stop_after_delay, stop_after_attempt
|
||||||
|
|
||||||
from mango_service_v3_py.api import MangoServiceV3Client
|
from mango_service_v4_py.api import MangoServiceV4Client
|
||||||
from mango_service_v3_py.dtos import Side, PlaceOrder
|
from mango_service_v4_py.dtos import Side, PlaceOrder
|
||||||
|
|
||||||
# based on https://github.com/BitMEX/sample-market-maker/blob/master/market_maker/market_maker.py
|
# based on https://github.com/BitMEX/sample-market-maker/blob/master/market_maker/market_maker.py
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ def toNearest(num, tickDec):
|
||||||
|
|
||||||
class MM:
|
class MM:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.mango_service_v3_client = MangoServiceV3Client()
|
self.mango_service_v4_client = MangoServiceV4Client()
|
||||||
self.market = None
|
self.market = None
|
||||||
self.start_position_buy = None
|
self.start_position_buy = None
|
||||||
self.start_position_sell = None
|
self.start_position_sell = None
|
||||||
|
@ -52,11 +52,11 @@ class MM:
|
||||||
|
|
||||||
# todo unused
|
# todo unused
|
||||||
@retry(stop=(stop_after_delay(10) | stop_after_attempt(5)), wait=wait_fixed(5))
|
@retry(stop=(stop_after_delay(10) | stop_after_attempt(5)), wait=wait_fixed(5))
|
||||||
def retry_wrapper(self, mango_service_v3_client_method, *arg):
|
def retry_wrapper(self, mango_service_v4_client_method, *arg):
|
||||||
getattr(self.mango_service_v3_client, mango_service_v3_client_method)(arg)
|
getattr(self.mango_service_v4_client, mango_service_v4_client_method)(arg)
|
||||||
|
|
||||||
def log_recent_trades(self) -> None:
|
def log_recent_trades(self) -> None:
|
||||||
trades = self.mango_service_v3_client.get_trades(MARKET)
|
trades = self.mango_service_v4_client.get_trades(MARKET)
|
||||||
recent_trades = [
|
recent_trades = [
|
||||||
trade
|
trade
|
||||||
for trade in trades
|
for trade in trades
|
||||||
|
@ -73,13 +73,13 @@ class MM:
|
||||||
logger.info("")
|
logger.info("")
|
||||||
|
|
||||||
def get_ticker(self):
|
def get_ticker(self):
|
||||||
self.market = self.mango_service_v3_client.get_market_by_market_name(MARKET)[0]
|
self.market = self.mango_service_v4_client.get_market_by_market_name(MARKET)[0]
|
||||||
self.start_position_buy = self.market.bid - self.market.price_increment
|
self.start_position_buy = self.market.bid - self.market.price_increment
|
||||||
self.start_position_sell = self.market.ask + self.market.price_increment
|
self.start_position_sell = self.market.ask + self.market.price_increment
|
||||||
|
|
||||||
self.positions = [
|
self.positions = [
|
||||||
position
|
position
|
||||||
for position in self.mango_service_v3_client.get_open_positions()
|
for position in self.mango_service_v4_client.get_open_positions()
|
||||||
if position.future == MARKET
|
if position.future == MARKET
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ class MM:
|
||||||
to_cancel = []
|
to_cancel = []
|
||||||
buys_matched = 0
|
buys_matched = 0
|
||||||
sells_matched = 0
|
sells_matched = 0
|
||||||
existing_orders = self.mango_service_v3_client.get_orders()
|
existing_orders = self.mango_service_v4_client.get_orders()
|
||||||
|
|
||||||
existing_orders = sorted(existing_orders, key=lambda order_: order_.price)
|
existing_orders = sorted(existing_orders, key=lambda order_: order_.price)
|
||||||
buy_orders = sorted(buy_orders, key=lambda order_: order_.price)
|
buy_orders = sorted(buy_orders, key=lambda order_: order_.price)
|
||||||
|
@ -145,7 +145,7 @@ class MM:
|
||||||
)
|
)
|
||||||
for order in to_cancel:
|
for order in to_cancel:
|
||||||
try:
|
try:
|
||||||
self.mango_service_v3_client.cancel_order_by_order_id(order.id)
|
self.mango_service_v4_client.cancel_order_by_order_id(order.id)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
logger.info("")
|
logger.info("")
|
||||||
|
@ -178,7 +178,7 @@ class MM:
|
||||||
f" |_ price {order.price}, side {order.side:4}, size {order.size}, value {order.price * order.size}"
|
f" |_ price {order.price}, side {order.side:4}, size {order.size}, value {order.price * order.size}"
|
||||||
)
|
)
|
||||||
for order in to_create:
|
for order in to_create:
|
||||||
self.mango_service_v3_client.place_order(
|
self.mango_service_v4_client.place_order(
|
||||||
PlaceOrder(
|
PlaceOrder(
|
||||||
market=MARKET,
|
market=MARKET,
|
||||||
side=order.side,
|
side=order.side,
|
||||||
|
@ -243,12 +243,11 @@ class MM:
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
mm = MM()
|
mm = MM()
|
||||||
logger.info("cancelling all orders...")
|
logger.info("cancelling all orders...")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
mm.mango_service_v3_client.cancel_all_orders()
|
mm.mango_service_v4_client.cancel_all_orders()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Exception: {e}")
|
logger.error(f"Exception: {e}")
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ from typing import List
|
||||||
import httpx
|
import httpx
|
||||||
from pydantic import parse_obj_as
|
from pydantic import parse_obj_as
|
||||||
|
|
||||||
from mango_service_v3_py.dtos import (
|
from mango_service_4_py.dtos import (
|
||||||
Position,
|
Position,
|
||||||
Balance,
|
Balance,
|
||||||
Market,
|
Market,
|
||||||
|
@ -32,7 +32,7 @@ def delayed(seconds):
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
class MangoServiceV3Client:
|
class MangoServiceV4Client:
|
||||||
def __init__(self, base_url=None, timeout=None):
|
def __init__(self, base_url=None, timeout=None):
|
||||||
self.timeout = timeout if timeout else 10.0
|
self.timeout = timeout if timeout else 10.0
|
||||||
if base_url:
|
if base_url:
|
||||||
|
@ -78,7 +78,9 @@ class MangoServiceV3Client:
|
||||||
)
|
)
|
||||||
return parse_obj_as(List[Candle], json.loads(response.text)["result"])
|
return parse_obj_as(List[Candle], json.loads(response.text)["result"])
|
||||||
|
|
||||||
def get_orders(self,) -> List[Order]:
|
def get_orders(
|
||||||
|
self,
|
||||||
|
) -> List[Order]:
|
||||||
response = httpx.get(f"{self.BASE_URL}/orders", timeout=self.timeout)
|
response = httpx.get(f"{self.BASE_URL}/orders", timeout=self.timeout)
|
||||||
return parse_obj_as(List[Order], json.loads(response.text)["result"])
|
return parse_obj_as(List[Order], json.loads(response.text)["result"])
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mango_service_v3_py.api import MangoServiceV3Client
|
from mango_service_v4_py.api import MangoServiceV4Client
|
||||||
from mango_service_v3_py.dtos import PlaceOrder
|
from mango_service_v4_py.dtos import PlaceOrder
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mango_service_v3_client():
|
def mango_service_v4_client():
|
||||||
return MangoServiceV3Client("http://localhost:3001/api", timeout=60.0)
|
return MangoServiceV4Client("http://localhost:3001/api", timeout=60.0)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def run_around_tests(mango_service_v3_client):
|
def run_around_tests(mango_service_v4_client):
|
||||||
# cleanup
|
# cleanup
|
||||||
mango_service_v3_client.cancel_all_orders()
|
mango_service_v4_client.cancel_all_orders()
|
||||||
orders = mango_service_v3_client.get_orders()
|
orders = mango_service_v4_client.get_orders()
|
||||||
assert len(orders) == 0
|
assert len(orders) == 0
|
||||||
yield
|
yield
|
||||||
# teardown
|
# teardown
|
||||||
assert True
|
assert True
|
||||||
|
|
||||||
|
|
||||||
def place_order(mango_service_v3_client, market):
|
def place_order(mango_service_v4_client, market):
|
||||||
mango_service_v3_client.place_order(
|
mango_service_v4_client.place_order(
|
||||||
PlaceOrder(
|
PlaceOrder(
|
||||||
market=market,
|
market=market,
|
||||||
side="buy",
|
side="buy",
|
||||||
|
@ -41,22 +41,22 @@ PERP_MARKET = [("BTC-PERP")]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("market", PERP_MARKET)
|
@pytest.mark.parametrize("market", PERP_MARKET)
|
||||||
def test_get_positions(mango_service_v3_client, market):
|
def test_get_positions(mango_service_v4_client, market):
|
||||||
positions = mango_service_v3_client.get_open_positions()
|
positions = mango_service_v4_client.get_open_positions()
|
||||||
assert len(positions) > 0
|
assert len(positions) > 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
||||||
def test_get_balances(mango_service_v3_client, market):
|
def test_get_balances(mango_service_v4_client, market):
|
||||||
balances = mango_service_v3_client.get_balances()
|
balances = mango_service_v4_client.get_balances()
|
||||||
assert len(balances) > 0
|
assert len(balances) > 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
||||||
def test_place_order(mango_service_v3_client, market):
|
def test_place_order(mango_service_v4_client, market):
|
||||||
mango_service_v3_client.cancel_all_orders()
|
mango_service_v4_client.cancel_all_orders()
|
||||||
place_order(mango_service_v3_client, market)
|
place_order(mango_service_v4_client, market)
|
||||||
orders = mango_service_v3_client.get_orders()
|
orders = mango_service_v4_client.get_orders()
|
||||||
assert len(orders) == 1
|
assert len(orders) == 1
|
||||||
|
|
||||||
order = orders[0]
|
order = orders[0]
|
||||||
|
@ -67,24 +67,24 @@ def test_place_order(mango_service_v3_client, market):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
||||||
def test_cancel_order_by_order_id(mango_service_v3_client, market):
|
def test_cancel_order_by_order_id(mango_service_v4_client, market):
|
||||||
place_order(mango_service_v3_client, market)
|
place_order(mango_service_v4_client, market)
|
||||||
|
|
||||||
orders = mango_service_v3_client.get_orders()
|
orders = mango_service_v4_client.get_orders()
|
||||||
order = orders[0]
|
order = orders[0]
|
||||||
mango_service_v3_client.cancel_order_by_order_id(order.id)
|
mango_service_v4_client.cancel_order_by_order_id(order.id)
|
||||||
|
|
||||||
orders = mango_service_v3_client.get_orders()
|
orders = mango_service_v4_client.get_orders()
|
||||||
assert len(orders) == 0
|
assert len(orders) == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
||||||
def test_cancel_order_by_client_id(mango_service_v3_client, market):
|
def test_cancel_order_by_client_id(mango_service_v4_client, market):
|
||||||
place_order(mango_service_v3_client, market)
|
place_order(mango_service_v4_client, market)
|
||||||
|
|
||||||
orders = mango_service_v3_client.get_orders()
|
orders = mango_service_v4_client.get_orders()
|
||||||
order = orders[0]
|
order = orders[0]
|
||||||
mango_service_v3_client.cancel_order_by_client_id(order.client_id)
|
mango_service_v4_client.cancel_order_by_client_id(order.client_id)
|
||||||
|
|
||||||
orders = mango_service_v3_client.get_orders()
|
orders = mango_service_v4_client.get_orders()
|
||||||
assert len(orders) == 0
|
assert len(orders) == 0
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mango_service_v3_py.api import MangoServiceV3Client
|
from mango_service_v4_py.api import MangoServiceV4Client
|
||||||
from mango_service_v3_py.dtos import PlaceOrder
|
from mango_service_v4_py.dtos import PlaceOrder
|
||||||
|
|
||||||
# Note: some endpoints only return useful data for mainnet, this is because the REST API service rely on
|
# Note: some endpoints only return useful data for mainnet, this is because the REST API service rely on
|
||||||
# other off chain REST services which only serve data for mainnet
|
# other off chain REST services which only serve data for mainnet
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mango_service_v3_client():
|
def mango_service_v4_client():
|
||||||
return MangoServiceV3Client("http://localhost:3000/api", timeout=60.0)
|
return MangoServiceV4Client("http://localhost:3000/api", timeout=60.0)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def run_around_tests(mango_service_v3_client):
|
def run_around_tests(mango_service_v4_client):
|
||||||
# cleanup
|
# cleanup
|
||||||
mango_service_v3_client.cancel_all_orders()
|
mango_service_v4_client.cancel_all_orders()
|
||||||
orders = mango_service_v3_client.get_orders()
|
orders = mango_service_v4_client.get_orders()
|
||||||
assert len(orders) == 0
|
assert len(orders) == 0
|
||||||
yield
|
yield
|
||||||
# teardown
|
# teardown
|
||||||
assert True
|
assert True
|
||||||
|
|
||||||
|
|
||||||
def place_order(mango_service_v3_client, market):
|
def place_order(mango_service_v4_client, market):
|
||||||
mango_service_v3_client.place_order(
|
mango_service_v4_client.place_order(
|
||||||
PlaceOrder(
|
PlaceOrder(
|
||||||
market=market,
|
market=market,
|
||||||
side="buy",
|
side="buy",
|
||||||
|
@ -44,26 +44,26 @@ PERP_MARKET = [("BTC-PERP")]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
||||||
def test_get_markets(mango_service_v3_client, market):
|
def test_get_markets(mango_service_v4_client, market):
|
||||||
markets = mango_service_v3_client.get_markets()
|
markets = mango_service_v4_client.get_markets()
|
||||||
assert len(markets) > 0
|
assert len(markets) > 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
||||||
def test_get_candles(mango_service_v3_client, market):
|
def test_get_candles(mango_service_v4_client, market):
|
||||||
candles = mango_service_v3_client.get_candles(market, 60, 1625922900, 1631214960)
|
candles = mango_service_v4_client.get_candles(market, 60, 1625922900, 1631214960)
|
||||||
print(candles)
|
print(candles)
|
||||||
assert len(candles) > 0
|
assert len(candles) > 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
||||||
def test_get_orderbook(mango_service_v3_client, market):
|
def test_get_orderbook(mango_service_v4_client, market):
|
||||||
ob = mango_service_v3_client.get_orderbook(market)
|
ob = mango_service_v4_client.get_orderbook(market)
|
||||||
assert len(ob.asks) > 0
|
assert len(ob.asks) > 0
|
||||||
assert len(ob.bids) > 0
|
assert len(ob.bids) > 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
@pytest.mark.parametrize("market", SPOT_AND_PERP_MARKETS)
|
||||||
def test_get_trades(mango_service_v3_client, market):
|
def test_get_trades(mango_service_v4_client, market):
|
||||||
trades = mango_service_v3_client.get_trades(market)
|
trades = mango_service_v4_client.get_trades(market)
|
||||||
assert len(trades) > 0
|
assert len(trades) > 0
|
||||||
|
|
Loading…
Reference in New Issue