Skip to content

Instantly share code, notes, and snippets.

@ImanMousavi
Created February 11, 2022 07:52
Show Gist options
  • Save ImanMousavi/440d90f88d7e3d57830fdad05bc93b80 to your computer and use it in GitHub Desktop.
Save ImanMousavi/440d90f88d7e3d57830fdad05bc93b80 to your computer and use it in GitHub Desktop.
# coding=utf-8
import random
import sys
import math
import hashlib
import hmac
import requests
import time
import urllib
from operator import itemgetter
import dateparser
import pytz
from datetime import datetime
openware_api_url = "https://www.example.com/api/v2/peatio"
openware_ranger_url = "wss://www.example.com/api/v2/ranger"
ApiKey = "xxxxxxxxxxxxxxxxxxxxxx"
ApiKeySecret = "xxxxxxxxxxxxxxxxxxxxxx"
TradingPair = "wikieth"
#TradingPair = "ethusd"
def date_to_milliseconds(date_str):
"""Convert UTC date to milliseconds
If using offset strings add "UTC" to date string e.g. "now UTC", "11 hours ago UTC"
See dateparse docs for formats http://dateparser.readthedocs.io/en/latest/
:param date_str: date in readable format, i.e. "January 01, 2018", "11 hours ago UTC", "now UTC"
:type date_str: str
"""
# get epoch value in UTC
epoch = datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc)
# parse our date string
d = dateparser.parse(date_str)
# if the date is not timezone aware apply UTC timezone
if d.tzinfo is None or d.tzinfo.utcoffset(d) is None:
d = d.replace(tzinfo=pytz.utc)
# return the difference in time
return int((d - epoch).total_seconds() * 1000.0)
def interval_to_milliseconds(interval):
"""Convert a Openware interval string to milliseconds
:param interval: Openware interval string, e.g.: 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w
:type interval: str
:return:
int value of interval in milliseconds
None if interval prefix is not a decimal integer
None if interval suffix is not one of m, h, d, w
"""
seconds_per_unit = {
"m": 60,
"h": 60 * 60,
"d": 24 * 60 * 60,
"w": 7 * 24 * 60 * 60,
}
try:
return int(interval[:-1]) * seconds_per_unit[interval[-1]] * 1000
except (ValueError, KeyError):
return None
class OpenwareAPIException(Exception):
def __init__(self, response):
self.code = 0
try:
json_res = response.json()
except ValueError:
self.message = 'Invalid JSON error message from Openware: {}'.format(response.text)
else:
self.message = response
# self.code = json_res['code']
# self.message = json_res['msg']
self.status_code = response.status_code
self.response = response
self.request = getattr(response, 'request', None)
def __str__(self): # pragma: no cover
return 'APIError(code=%s): %s' % (self.code, self.message)
class OpenwareRequestException(Exception):
def __init__(self, message):
self.message = message
def __str__(self):
return 'OpenwareRequestException: %s' % self.message
class OpenwareOrderException(Exception):
def __init__(self, code, message):
self.code = code
self.message = message
def __str__(self):
return 'OpenwareOrderException(code=%s): %s' % (self.code, self.message)
class OpenwareOrderMinAmountException(OpenwareOrderException):
def __init__(self, value):
message = "Amount must be a multiple of %s" % value
super(OpenwareOrderMinAmountException, self).__init__(-1013, message)
class OpenwareOrderMinPriceException(OpenwareOrderException):
def __init__(self, value):
message = "Price must be at least %s" % value
super(OpenwareOrderMinPriceException, self).__init__(-1013, message)
class OpenwareOrderMinTotalException(OpenwareOrderException):
def __init__(self, value):
message = "Total must be at least %s" % value
super(OpenwareOrderMinTotalException, self).__init__(-1013, message)
class OpenwareOrderUnknownSymbolException(OpenwareOrderException):
def __init__(self, value):
message = "Unknown symbol %s" % value
super(OpenwareOrderUnknownSymbolException, self).__init__(-1013, message)
class OpenwareOrderInactiveSymbolException(OpenwareOrderException):
def __init__(self, value):
message = "Attempting to trade an inactive symbol %s" % value
super(OpenwareOrderInactiveSymbolException, self).__init__(-1013, message)
class OpenwareWithdrawException(Exception):
def __init__(self, message):
if message == u'参数异常':
message = 'Withdraw to this address through the website first'
self.message = message
def __str__(self):
return 'OpenwareWithdrawException: %s' % self.message
class OpenwareClient(object):
ORDER_STATUS_NEW = 'NEW'
ORDER_STATUS_PARTIALLY_FILLED = 'PARTIALLY_FILLED'
ORDER_STATUS_FILLED = 'FILLED'
ORDER_STATUS_CANCELED = 'CANCELED'
ORDER_STATUS_PENDING_CANCEL = 'PENDING_CANCEL'
ORDER_STATUS_REJECTED = 'REJECTED'
ORDER_STATUS_EXPIRED = 'EXPIRED'
KLINE_INTERVAL_1MINUTE = '1m'
KLINE_INTERVAL_3MINUTE = '3m'
KLINE_INTERVAL_5MINUTE = '5m'
KLINE_INTERVAL_15MINUTE = '15m'
KLINE_INTERVAL_30MINUTE = '30m'
KLINE_INTERVAL_1HOUR = '1h'
KLINE_INTERVAL_2HOUR = '2h'
KLINE_INTERVAL_4HOUR = '4h'
KLINE_INTERVAL_6HOUR = '6h'
KLINE_INTERVAL_8HOUR = '8h'
KLINE_INTERVAL_12HOUR = '12h'
KLINE_INTERVAL_1DAY = '1d'
KLINE_INTERVAL_3DAY = '3d'
KLINE_INTERVAL_1WEEK = '1w'
KLINE_INTERVAL_1MONTH = '1M'
SIDE_BUY = 'buy'
SIDE_SELL = 'sell'
ORDER_TYPE_LIMIT = 'limit'
ORDER_TYPE_MARKET = 'market'
TIME_IN_FORCE_GTC = 'GTC' # Good till cancelled
TIME_IN_FORCE_IOC = 'IOC' # Immediate or cancel
TIME_IN_FORCE_FOK = 'FOK' # Fill or kill
ORDER_RESP_TYPE_ACK = 'ACK'
ORDER_RESP_TYPE_RESULT = 'RESULT'
ORDER_RESP_TYPE_FULL = 'FULL'
# For accessing the data returned by Client.aggregate_trades().
AGG_ID = 'a'
AGG_PRICE = 'p'
AGG_QUANTITY = 'q'
AGG_FIRST_TRADE_ID = 'f'
AGG_LAST_TRADE_ID = 'l'
AGG_TIME = 'T'
AGG_BUYER_MAKES = 'm'
AGG_BEST_MATCH = 'M'
def __init__(self, api_key, api_secret, api_url):
"""Openware API Client constructor
"""
self.api_key = api_key
self.api_secret = api_secret
self.api_url = api_url
self.session = self._init_session()
self.version()
def _init_session(self):
timestamp = str(time.time() * 1000)
signature = self._generate_signature(timestamp)
session = requests.session()
session.headers.update({'Accept': 'application/json',
'User-Agent': 'openware/python',
'X-Auth-Apikey': self.api_key,
'X-Auth-Nonce': timestamp,
'X-Auth-Signature': signature})
return session
def update_headers(self):
timestamp = str(time.time() * 1000)
signature = self._generate_signature(timestamp)
self.session.headers.update({'Accept': 'application/json',
'User-Agent': 'openware/python',
'X-Auth-Apikey': self.api_key,
'X-Auth-Nonce': timestamp,
'X-Auth-Signature': signature})
return self.session
def _create_api_uri(self, path):
return "%s%s" % (self.api_url, path)
def _generate_signature(self, timestamp):
query_string = "%s%s" % (timestamp, self.api_key)
m = hmac.new(self.api_secret.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256)
return m.hexdigest()
def _request(self, method, uri, force_params=False, **kwargs):
data = kwargs.get('data', None)
if data and isinstance(data, dict):
kwargs['data'] = data
# if get request assign data array to params value for requests lib
if data and (method == 'get' or force_params):
kwargs['params'] = kwargs['data']
del(kwargs['data'])
self.update_headers()
response = getattr(self.session, method)(uri, **kwargs)
return self._handle_response(response)
def _request_api(self, method, path, **kwargs):
uri = self._create_api_uri(path)
return self._request(method, uri, **kwargs)
def _handle_response(self, response):
if not str(response.status_code).startswith('2'):
raise OpenwareAPIException(response)
try:
resp = response.json()
return resp
except ValueError:
raise OpenwareRequestException('Invalid Response: %s' % response.text)
def _get(self, path, **kwargs):
return self._request_api('get', path, **kwargs)
def _post(self, path, **kwargs):
return self._request_api('post', path, **kwargs)
def _put(self, path, **kwargs):
return self._request_api('put', path, **kwargs)
def _delete(self, path, **kwargs):
#return self._request_api('delete', path, signed, version, **kwargs)
return self._request_api('delete', path, **kwargs)
def version(self):
return self._get("/public/timestamp")
def get_markets(self):
return self._get('/public/markets')
def get_currencies(self):
return self._get('/public/currencies')
def get_server_time(self):
return self._get('/public/timestamp')
def get_balances(self):
return self._get('/account/balances')
def get_trade_fee(self):
return self._get('/public/trading_fees')
def get_my_trades(self, **params):
return self._get("/market/trades", data=params)
def get_order_by_id(self, **params):
id = params.get('id')
result = self._get("/market/orders/{}".format(id))
return result
def get_order(self, **params):
result = self._get("/market/orders", data=params)
return result
def get_snapshot(self):
return self._get("/public/markets/" + TradingPair + "/depth")
def get_tickers(self):
return self._get("/public/markets/tickers")
def get_deposit_address(self, currency):
return self._get("/account/deposit_address/%s" % currency)
def withdraw(self, **params):
return self._post("/account/withdraws", data=params)
def create_order(self, **params):
"""
Send in a new order
"""
return self._post('/market/orders', data=params)
def order_market(self, **params):
"""
Send in a new market order
"""
params.update({
'ord_type': self.ORDER_TYPE_MARKET
})
return self.create_order(**params)
def order_limit(self, **params):
"""
Send in a new market order
"""
params.update({
'ord_type': self.ORDER_TYPE_LIMIT
})
return self.create_order(**params)
def order_market_buy(self, **params):
"""
Send in a new market buy order
"""
params.update({
'side': self.SIDE_BUY
})
return self.order_market(**params)
def order_limit_buy(self, **params):
"""
Send in a new market buy order
"""
params.update({
'side': self.SIDE_BUY
})
return self.order_limit(**params)
def order_market_sell(self, **params):
"""
Send in a new market sell order
"""
params.update({
'side': self.SIDE_SELL
})
return self.order_market(**params)
def order_limit_sell(self, **params):
"""
Send in a new market sell order
"""
params.update({
'side': self.SIDE_SELL
})
return self.order_limit(**params)
def cancel_order(self, **params):
"""
Cancel order
"""
id = params.get('id')
resp = self._post('/market/orders/%s/cancel' % id)
if resp:
print("Order Canceled " + resp['market'] + " "
+ str(resp['id']) + " " + resp['uuid']
+ " " + resp['state']
+ " price: " + resp['price']
+ " volume: " + resp['origin_volume'])
return resp
else:
print("Can not deserialise order")
return None
####################################################################
####################################################################
####################################################################
client = OpenwareClient(ApiKey, ApiKeySecret, openware_api_url)
NewOrders = []
#print(client.version())
print(client.get_server_time())
def PrintMarkets():
print("Markets:")
marketsJSON = client.get_markets()
for row in marketsJSON:
print("\t" + row['name'] + " MinPrice: " + str(row['min_price'])
+ " MaxPrice: " + str(row['max_price'])
+ " MinAmount: " + str(row['min_amount'])
+ " PricePrecision: " + str(row['price_precision'])
+ " AmountPrecision: " + str(row['amount_precision']))
def PrintBalances():
print("Assets:")
balancesJSON = client.get_balances()
for row in balancesJSON:
print("\t" + row['currency'] + " balance: " + row['balance'] + " locked: " + row['locked'])
def PrintOrders():
print("Orders:")
ordersJSON = client.get_order()
for order in ordersJSON:
if order['market'] == TradingPair and order['ord_type'] == "limit":
if order["state"] == "pending" or order["state"] == "wait":
print("\t" + order['market'] + " " + str(order['id'])
+ " " + order['side'] + " price: " + order['price']
+ " volume: " + order['origin_volume']
+ " " + order['state']
+ " " + order['ord_type']
+ " TradesCount: " + str(order['trades_count']))
def CancelOrders():
for order in NewOrders:
if(order['state'] == "pending" or order['state'] == "wait"):
resp = client.cancel_order(id=order['id'])
if resp:
NewOrders.remove(order)
def ExecuteOrder(orderType, orderVolume, orderPrice):
side = orderType # sell or buy
volume = "{:.5f}".format(orderVolume)
price = "{:.4f}".format(orderPrice)
ordType = "limit"
data = "{\"market\": \"" + TradingPair + "\", \"volume\": \"" + volume + "\", \"price\": \"" + price + "\", \"side\": \"" + side + "\", \"ord_type\": \"" + ordType + "\"}";
resp = client._post("/market/orders", data=data)
if resp:
print("Order Executed [" + ordType + "] " + resp['market']
+ " " + str(resp['id'])
+ " " + resp['uuid']
+ " " + resp['state']
+ " price: " + resp['price']
+ " volume: " + resp['origin_volume'])
return resp
else:
print("Can not deserialise order")
return None
def getMinAsk(asksList):
return float(min(asksList, key = lambda x: float(x[0]))[0])
def getMaxBid(bidList):
return float(max(bidList, key = lambda x: float(x[0]))[0])
def NextFloat(min, max):
import random
random = random.uniform(0, 1)
diff = max - min
r = random * diff
return min + r
def IssueNewProposal():
numOrders = 10
askSpread = 0.01
bidSpread = 0.01
offset = 0.0001
minVolume = 0.01
maxVolume = 11.57000
marketDepth = client.get_snapshot()
tickers = client.get_tickers()
lastPrice = float(tickers[TradingPair]['ticker']['last'])
if(len(marketDepth['asks']) > 0 and len(marketDepth['bids']) < numOrders):
minPriceSell = getMinAsk(marketDepth['asks'])
for i in range(0, numOrders):
volume = NextFloat(minVolume, maxVolume)
price = NextFloat(((lastPrice - offset) - (numOrders * bidSpread)), (minPriceSell - offset))
try:
order = ExecuteOrder("buy", volume, price)
if order is not None:
NewOrders.append(order)
except Exception as e:
print("ERROR couldn't execute BUY order. Price:" + str(price) + " volume: " + str(volume))
elif len(marketDepth['bids']) == 0:
volume = NextFloat(minVolume, maxVolume)
price = NextFloat(((lastPrice - offset) - (numOrders * bidSpread)), (lastPrice - offset))
try:
order = ExecuteOrder("buy", volume, price)
if order is not None:
NewOrders.append(order)
except:
print("ERROR couldn't execute BUY order. Price:" + str(price) + " volume: " + str(volume))
if(len(marketDepth['bids']) > 0 and len(marketDepth['asks']) < numOrders):
maxPriceBuy = getMaxBid(marketDepth['bids'])
for i in range(0, numOrders):
volume = NextFloat(minVolume, maxVolume)
price = NextFloat(maxPriceBuy + offset, maxPriceBuy + offset + (numOrders * askSpread))
try:
order = ExecuteOrder("sell", volume, price)
if order is not None:
NewOrders.append(order)
except:
print("ERROR couldn't execute SELL order. Price:" + str(price) + " volume: " + str(volume))
elif len(marketDepth['asks']) == 0:
volume = NextFloat(minVolume, maxVolume)
price = NextFloat(lastPrice + offset, lastPrice + offset + (numOrders * askSpread))
try:
order = ExecuteOrder("sell", volume, price)
if order is not None:
NewOrders.append(order)
except:
print("ERROR couldn't execute SELL order. Price:" + str(price) + " volume: " + str(volume))
def ConvertToRadians(angle):
return (math.pi / 180.0) * angle
def ExecuteMakerBot():
print("Maker Bot.")
CancelOrders()
IssueNewProposal()
stepSize = 0.01
stepMode = 0
def ExecuteTakerBot():
global stepMode
print("Taker Bot.")
minVolume = 0.0001
MAX_Volume = 1.0
MAX_SELL_Volume = 1.0
numTakerBots = 4
amplitude = 100
if stepMode >= 360:
stepMode = 0
stepSize = NextFloat(0.01, 10.00)
for k in range(0, numTakerBots):
marketDepth = client.get_snapshot()
tickers = client.get_tickers()
lastPrice = float(tickers[TradingPair]['ticker']['last'])
if NextFloat(0, 10) >= 2:
# BUY
if len(marketDepth['asks']) > 0:
# Get minimum buying price and max volume.
minBuyPrice = sys.float_info.max
maxVolume = minVolume
found = False
for i in range(0, len(marketDepth['asks'])):
ask = marketDepth['asks'][i]
askP = float(ask[0])
if askP < minBuyPrice and askP >= lastPrice:
minBuyPrice = askP
maxVolume = float(ask[1])
found = True
volume = NextFloat(minVolume, amplitude * math.sin(ConvertToRadians(stepMode * (maxVolume % MAX_Volume))))
#volume = NextFloat(minVolume, maxVolume % MAX_Volume)
price = minBuyPrice
if price >= lastPrice and found:
try:
order = ExecuteOrder("buy", volume, price)
except:
print("ERROR couldn't execute BUY order. Price:" + str(price) + " volume: " + str(volume))
else:
# SELL
if len(marketDepth['bids']) > 0:
# Get maximum selling price and max volume.
maxSellPrice = sys.float_info.min
maxVolume = minVolume
found = False
for i in range(0, len(marketDepth['bids'])):
bid = marketDepth['bids'][i]
bidP = float(bid[0])
if bidP > maxSellPrice and bidP <= lastPrice:
maxSellPrice = bidP
maxVolume = float(bid[1])
found = True
volume = NextFloat(minVolume, amplitude * math.sin(ConvertToRadians(stepMode * (maxVolume % MAX_SELL_Volume))))
#volume = NextFloat(minVolume, maxVolume % MAX_SELL_Volume)
price = maxSellPrice
if price <= lastPrice and found:
try:
order = ExecuteOrder("sell", volume, price)
except:
print("ERROR couldn't execute SELL order. Price:" + str(price) + " volume: " + str(volume))
# Begin program.
PrintMarkets()
PrintBalances()
ticks = 0
while(True):
#if (ticks == 0 or ticks % 5 == 0):
PrintOrders()
ExecuteMakerBot()
ExecuteTakerBot()
time.sleep(10.0)
ticks += 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment