Permalink
Fetching contributors…
Cannot retrieve contributors at this time
1021 lines (913 sloc) 44.6 KB
#! /usr/bin/env python
"""
The MIT License (MIT)
Copyright (c) 2015 creon (creon.nu@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.
"""
import sys
import json
import hmac
import time
import urllib
import urllib2
import random
import hashlib
import httplib
import threading
import datetime
class Exchange(object):
def __init__(self, fee):
self.fee = fee
self._shift = 1
self._nonce = 0
def adjust(self, error):
if 'exception caught:' not in error:
self._shift = ((self._shift + 7) % 200) - 100 # -92 15 -78 29 -64 43 -50 57 ...
def nonce(self, factor=1000.0):
n = int((time.time() + self._shift) * float(factor))
if self._nonce >= n:
n = self._nonce + 10
self._nonce = n
return n
class Bittrex(Exchange):
def __init__(self):
super(Bittrex, self).__init__(0.0025)
self.placed = {}
self.closed = []
def __repr__(self):
return "bittrex"
def adjust(self, error):
pass
def post(self, method, params, key, secret, throttle=5):
data = 'https://bittrex.com/api/v1.1' + method + '?apikey=%s&nonce=%d&' % (
key, self.nonce()) + urllib.urlencode(params)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
headers = {'apisign': sign}
connection = httplib.HTTPSConnection('bittrex.com', timeout=10)
connection.request('GET', data, headers=headers)
response = json.loads(connection.getresponse().read())
if throttle > 0 and not response['success'] and 'THROTTLED' in response['message']:
time.sleep(2)
return self.post(method, params, key, secret, throttle - 1)
return response
def get(self, method, params):
data = 'https://bittrex.com/api/v1.1' + method + '?' + urllib.urlencode(params)
connection = httplib.HTTPSConnection('bittrex.com', timeout=10)
connection.request('GET', data, headers={})
return json.loads(connection.getresponse().read())
def cancel_orders(self, unit, side, key, secret):
response = self.post('/market/getopenorders', {'market': "%s-NBT" % unit.upper()}, key, secret)
if not response['success']:
response['error'] = response['message']
return response
if not response['result']:
response['result'] = []
response['removed'] = []
response['amount'] = 0.0
for order in response['result']:
if side == 'all' or (side == 'bid' and 'BUY' in order['OrderType']) or (
side == 'ask' and 'SELL' in order['OrderType']):
ret = self.post('/market/cancel', {'uuid': order['OrderUuid']}, key, secret)
if not ret['success'] and ret['message'] != "ORDER_NOT_OPEN":
if not 'error' in response: response = {'error': ""}
response['error'] += "," + ret['message']
else:
response['removed'].append(order['OrderUuid'])
response['amount'] += order['Quantity']
if not 'error' in response and key in self.placed and unit in self.placed[key]:
if side == 'all':
self.placed[key][unit]['bid'] = False
self.placed[key][unit]['ask'] = False
else:
self.placed[key][unit][side] = False
return response
def place_order(self, unit, side, key, secret, amount, price):
ret = self.cancel_orders(unit, side, key, secret)
if 'error' in ret: return ret
amount += ret['amount']
if side == 'bid':
amount *= (1.0 - self.fee)
params = {'market': "%s-NBT" % unit.upper(), "rate": price, "quantity": amount}
response = self.post('/market/buylimit' if side == 'bid' else '/market/selllimit', params, key, secret)
if response['success']:
response['id'] = response['result']['uuid']
if not key in self.placed:
self.placed[key] = {}
if not unit in self.placed[key]:
self.placed[key][unit] = {'bid': False, 'ask': False}
self.placed[key][unit][side] = response['id']
else:
response['error'] = response['message']
response['residual'] = ret['amount']
return response
def get_balance(self, unit, key, secret):
response = self.post('/account/getbalance', {'currency': unit.upper()}, key, secret)
if response['success']:
try:
response['balance'] = float(response['result']['Available'])
except:
response['balance'] = 0.0
else:
response['error'] = response['message']
return response
def get_price(self, unit):
response = self.get('/public/getticker', {'market': '%s-NBT' % unit})
if response['success']:
response.update({'bid': response['result']['Bid'], 'ask': response['result']['Ask']})
else:
response['error'] = response['message']
return response
def create_request(self, unit, key=None, secret=None):
if not secret or not key:
return None, None
uuids = []
if key in self.placed and unit in self.placed[key]:
if self.placed[key][unit]['bid']:
uuids.append(self.placed[key][unit]['bid'])
if self.placed[key][unit]['ask']:
uuids.append(self.placed[key][unit]['ask'])
requests = []
signatures = []
for uuid in uuids:
data = 'https://bittrex.com/api/v1.1/account/getorder?apikey=%s&nonce=%d&uuid=%s' % (
key, self.nonce(), uuid)
requests.append(data)
signatures.append(hmac.new(secret, data, hashlib.sha512).hexdigest())
return {'requests': json.dumps(requests), 'signs': json.dumps(signatures)}, None
def validate_request(self, key, unit, data, signs):
orders = []
last_error = ""
requests = json.loads(data['requests'])
signs = json.loads(data['signs'])
if len(requests) != len(signs):
return {
'error': 'missmatch between requests and signatures (%d vs %d)' % (len(data['requests']), len(signs))}
if len(requests) > 2:
return {'error': 'too many requests received: %d' % len(requests)}
connection = httplib.HTTPSConnection('bittrex.com', timeout=5)
for data, sign in zip(requests, signs):
uuid = data.split('=')[-1]
if not uuid in self.closed:
headers = {'apisign': sign}
connection.request('GET', data, headers=headers)
response = json.loads(connection.getresponse().read())
if response['success']:
try:
opened = int(
datetime.datetime.strptime(response['result']['Opened'], '%Y-%m-%dT%H:%M:%S.%f').strftime(
"%s"))
except:
opened = 0
try:
closed = int(
datetime.datetime.strptime(response['result']['Closed'], '%Y-%m-%dT%H:%M:%S.%f').strftime(
"%s"))
except:
closed = sys.maxint
if closed < time.time() - 60:
self.closed.append(uuid)
orders.append({
'id': response['result']['OrderUuid'],
'price': response['result']['Limit'],
'type': 'ask' if 'SELL' in response['result']['Type'] else 'bid',
'amount': response['result']['QuantityRemaining'],
# if not closed == sys.maxint else response['result']['Quantity'],
'opened': opened,
'closed': closed,
})
else:
last_error = response['message']
if not orders and last_error != "":
return {'error': last_error}
return orders
class Cryptsy(Exchange):
def __init__(self):
super(Cryptsy, self).__init__(0.002)
self.market_codes = {}
self.currency_codes = {}
self.key = None
self.secret = None
def __repr__(self):
return "cryptsy"
def adjust(self, error):
pass
def post(self, params, key, secret):
self.key = key
self.secret = secret
request = {'nonce': self.nonce()}
request.update(params)
data = urllib.urlencode(request)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
headers = {'Sign': sign, 'Key': key}
return json.loads(urllib2.urlopen(urllib2.Request(
url='https://api.cryptsy.com/api', data=data,
headers=headers)).read())
def get(self, method, params, key, secret):
self.key = key
self.secret = secret
request = {'nonce': self.nonce()}
request.update(params)
data = urllib.urlencode(request)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
headers = {'Sign': sign, 'Key': key}
return json.loads(urllib2.urlopen(urllib2.Request(
url='https://api.cryptsy.com/api/{0}?{1}'.format(method, data),
headers=headers)).read())
def get_market_codes(self, key, secret):
if self.market_codes:
return self.market_codes
market_data = self.post({'method': 'getmarkets'}, key, secret)
for market in market_data['return']:
self.market_codes[market['label']] = market['marketid']
return self.market_codes
def get_market_id(self, unit, key, secret):
codes = self.get_market_codes(key, secret)
return codes['NBT/{0}'.format(unit.upper())]
def cancel_orders(self, unit, side, key, secret):
response = self.post({'method': 'myorders',
'marketid': self.get_market_id(unit, key, secret)}, key,
secret)
if int(response['success']) == 0:
return response
for order in response['return']:
if side == 'all' or (side == 'bid' and order['ordertype'] == 'Buy') or (
side == 'ask' and order['ordertype'] == 'Sell'):
ret = self.post({'method': 'cancelorder', 'orderid': order['orderid']},
key, secret)
if int(ret['success']) == 0:
if isinstance(response, list):
response = {'error': ""}
response['error'] += "," + ret['error']
return response
def get_fee(self, unit, side, amount, price, key, secret):
params = {'method': 'calculatefees',
'ordertype': 'Buy' if side == 'bid' else 'Sell',
'quantity': amount,
'price': price,
'marketid': self.get_market_id(unit, key, secret)}
response = self.post(params, key, secret)
if int(response['success']) == 0:
return self.fee
return (float(response['return']['fee']) / float(price)) / 100
def place_order(self, unit, side, key, secret, amount, price):
params = {'method': 'createorder',
'marketid': self.get_market_id(unit, key, secret),
'ordertype': 'Buy' if side == 'bid' else 'Sell',
'quantity':
(str(float(amount) - float(self.get_fee(unit, side, amount,
price, key, secret)))) if
side == 'bid' else amount,
'price': price}
response = self.post(params, key, secret)
if int(response['success']) > 0:
response['id'] = int(response['orderid'])
return response
def get_balance(self, unit, key, secret):
response = self.post({'method': 'getinfo'}, key, secret)
if int(response['success']) > 0:
response['balance'] = float(
response['return']['balances_available'][unit.upper()])
return response
def get_price(self, unit):
response = self.post({'method': 'depth', 'marketid': self.get_market_id(
unit,
self.key,
self.secret)}, self.key, self.secret)
if int(response['success']) > 0:
response.update({'bid': None, 'ask': None})
if response['return']['buy']:
response['bid'] = float(response['return']['buy'][0][0])
if response['return']['sell']:
response['ask'] = float(response['return']['sell'][0][0])
return response
def create_request(self, unit, key=None, secret=None):
if not secret:
return None, None
request = {'method': 'myorders',
'marketid': self.get_market_id(unit, key, secret),
'nonce': self.nonce()}
data = urllib.urlencode(request)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
return request, sign
def validate_request(self, key, unit, data, sign):
headers = {'Sign': sign, 'Key': key}
ret = urllib2.urlopen(urllib2.Request('https://api.cryptsy.com/api',
urllib.urlencode(data), headers), timeout=5)
response = json.loads(ret.read())
if int(response['success']) == 0:
return response
return [{'id': int(order['orderid']),
'price': float(order['price']),
'type': 'ask' if order['ordertype'] == 'Sell' else 'bid',
'amount': float(order['quantity'])} for order in response['return']]
class SouthXChange(Exchange):
def __init__(self):
super(SouthXChange, self).__init__(0.002)
def __repr__(self):
return 'southxchange'
def adjust(self, error):
pass
def post(self, method, key, secret, params=None):
data = {'nonce': self.nonce(), 'key': key}
if params is not None:
data.update(params)
data = json.dumps(data)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
headers = {'Hash': sign, 'Content-Type': 'application/json'}
url = 'https://www.southxchange.com/api/{0}/'.format(method)
try:
request = urllib2.Request(url=url, data=data, headers=headers)
except urllib2.HTTPError as e:
if e.code == 500:
return {'error': 'API returned 500 error'}
return {'error': 'API error'}
return json.loads(urllib2.urlopen(request).read())
def get(self, method, unit=None):
url = 'https://www.southxchange.com/api/{0}/'.format(method)
if unit is not None:
url += unit.upper() + "/NBT"
try:
request = urllib2.Request(url=url)
except urllib2.HTTPError as e:
if e.code == 500:
return {'error': 'API returned 500 error'}
return {'error': 'API error'}
return json.loads(urllib2.urlopen(request).read())
def get_price(self, unit):
response = self.get('price', unit)
if 'error' not in response:
response.update({'bid': None, 'ask': None})
response['bid'] = response['Bid']
response['ask'] = response['Ask']
return response
def place_order(self, unit, side, key, secret, amount, price):
method = 'placeOrder'
params = {'listingCurrency': unit.upper(),
'referenceCurrency': 'NBT',
'type': 'sell' if side == 'bid' else 'buy',
'amount': (round(float(amount) * float(price), 4)) if side == 'bid'
else (round(float(amount) / float(price), 4)),
'limitPrice': round(1 / float(price), 4)}
response = self.post(method, key, secret, params)
if 'error' in response:
return response
return {'id': response}
def cancel_orders(self, unit, side, key, secret):
response = self.post('listOrders', key, secret)
if 'error' in response:
return response
for order in response:
if side == 'all' or (side == 'bid' and order['Type'] == 'sell') or \
(side == 'ask' and order['Type'] == 'buy'):
if order['ListingCurrency'] == unit.upper() and \
order['ReferenceCurrency'] == 'NBT':
ret = self.post('cancelOrder', key, secret, {'orderCode': order['Code']})
if 'error' in ret:
if isinstance(response, list):
response = {'error': ""}
response['error'] += "," + ret['error']
print response
return response
def get_balance(self, unit, key, secret):
response = self.post('listBalances', key, secret)
if 'error' in response:
response = []
unit = unit.upper()
for balance in response:
if balance['Currency'] == unit:
return {'balance': balance['Available']}
return {'balance': 0}
def create_request(self, unit, key=None, secret=None):
if not secret and not key:
return None, None
request = {'nonce': self.nonce(), 'key': key}
data = json.dumps(request)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
return {'data': data}, sign
def validate_request(self, key, unit, data, sign):
url = 'https://www.southxchange.com/api/listOrders'
headers = {'Hash': sign, 'Content-Type': 'application/json'}
request = urllib2.Request(url=url, data=data['data'], headers=headers)
response = json.loads(urllib2.urlopen(request).read())
return [{
'id': order['Code'],
'price': round(1 / float(order['LimitPrice']), 8),
'type': 'bid' if order['Type'] == 'sell' else 'ask',
'amount': round(float(order['Amount']) * float(order['LimitPrice']),
8) if order['Type'] == 'sell' else round(float(
order['Amount']) / float(order['LimitPrice']), 8)
} for order in response]
class Poloniex(Exchange):
def __init__(self):
super(Poloniex, self).__init__(0.002)
def __repr__(self):
return "poloniex"
def adjust(self, error):
if "Nonce must be greater than" in error: # (TODO: regex)
if ':' in error: error = error.split(':')[1].strip()
error = error.replace('.', '').split()
self._shift += 100.0 + (int(error[5]) - int(error[8])) / 1000.0
else:
self._shift = self._shift + 100.0
def post(self, method, params, key, secret):
request = {'nonce': self.nonce(), 'command': method}
request.update(params)
data = urllib.urlencode(request)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
headers = {'Sign': sign, 'Key': key}
return json.loads(urllib2.urlopen(urllib2.Request('https://poloniex.com/tradingApi', data, headers)).read())
def cancel_orders(self, unit, side, key, secret):
response = self.post('returnOpenOrders', {'currencyPair': "%s_NBT" % unit.upper()}, key, secret)
if 'error' in response: return response
for order in response:
if side == 'all' or (side == 'bid' and order['type'] == 'buy') or (
side == 'ask' and order['type'] == 'sell'):
ret = self.post('cancelOrder',
{'currencyPair': "%s_NBT" % unit.upper(), 'orderNumber': order['orderNumber']}, key,
secret)
if 'error' in ret:
if isinstance(response, list): response = {'error': ""}
response['error'] += "," + ret['error']
return response
def place_order(self, unit, side, key, secret, amount, price):
params = {'currencyPair': "%s_NBT" % unit.upper(), "rate": price, "amount": amount}
response = self.post('buy' if side == 'bid' else 'sell', params, key, secret)
if not 'error' in response:
response['id'] = int(response['orderNumber'])
return response
def get_balance(self, unit, key, secret):
response = self.post('returnBalances', {}, key, secret)
if not 'error' in response:
response['balance'] = float(response[unit.upper()])
return response
def get_price(self, unit):
response = json.loads(urllib2.urlopen('https://poloniex.com/public?' +
urllib.urlencode({'command': 'returnOrderBook',
'currencyPair': "%s_NBT" % unit.upper(), 'depth': 1}),
timeout=5).read())
if not 'error' in response:
response.update({'bid': None, 'ask': None})
if response['bid']: response['bid'] = float(response['bid'][0])
if response['ask']: response['ask'] = float(response['ask'][0])
return response
def create_request(self, unit, key=None, secret=None):
if not secret: return None, None
request = {'command': 'returnOpenOrders', 'nonce': self.nonce(), 'currencyPair': "%s_NBT" % unit.upper()}
data = urllib.urlencode(request)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
return request, sign
def validate_request(self, key, unit, data, sign):
headers = {'Sign': sign, 'Key': key}
ret = urllib2.urlopen(urllib2.Request('https://poloniex.com/tradingApi', urllib.urlencode(data), headers),
timeout=5)
response = json.loads(ret.read())
if 'error' in response: return response
return [{
'id': int(order['orderNumber']),
'price': float(order['rate']),
'type': 'ask' if order['type'] == 'sell' else 'bid',
'amount': float(order['amount']),
} for order in response]
class CCEDK(Exchange):
def __init__(self):
super(CCEDK, self).__init__(0.002)
self.pair_id = {}
self.currency_id = {}
failed = False
while not self.pair_id or not self.currency_id:
try:
response = None
if not self.pair_id:
url = 'https://www.ccedk.com/api/v1/stats/marketdepthfull'
response = json.loads(urllib2.urlopen(urllib2.Request(url), timeout=15).read())
for unit in response['response']['entities']:
if unit['pair_name'][:4] == 'nbt/':
self.pair_id[unit['pair_name'][4:]] = unit['pair_id']
if not self.currency_id:
url = 'https://www.ccedk.com/api/v1/currency/list'
response = json.loads(urllib2.urlopen(urllib2.Request(url), timeout=15).read())
for unit in response['response']['entities']:
self.currency_id[unit['iso'].lower()] = unit['currency_id']
except Exception as e:
if response and not response['response']:
self.adjust(",".join(response['errors'].values()))
if failed:
print >> sys.stderr, "could not retrieve ccedk ids, will adjust shift to", self._shift, \
"reason:", ",".join(response['errors'].values())
else:
print >> sys.stderr, "could not retrieve ccedk ids, server is unreachable", e
failed = True
time.sleep(1)
def __repr__(self):
return "ccedk"
def nonce(self, factor=1.0):
n = int(time.time() + self._shift)
if n == self._nonce:
n = self._nonce + 1
self._nonce = n
return n
def adjust(self, error):
if "incorrect range" in error: # (TODO: regex)
if ':' in error:
error = error.split(':')[1].strip()
try:
minimum = int(error.strip().split()[-3].replace('`', ''))
maximum = int(error.strip().split()[-1].replace('`', ''))
current = int(error.strip().split()[-7].split('`')[3])
except:
self._shift += random.randrange(-10, 10)
else:
if current < maximum:
new_shift = (minimum + 2 * maximum) / 3 - current
if new_shift < 0:
new_shift = 10
else:
new_shift = (2 * minimum + maximum) / 3 - current
if new_shift != 0:
self._shift += new_shift
else:
self._shift += random.randrange(-10, 10)
else:
self._shift += random.randrange(-10, 10)
def post(self, method, params, key, secret):
request = {'nonce': self.nonce()} # TODO: check for unique nonce
request.update(params)
data = urllib.urlencode(request)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
headers = {"Content-type": "application/x-www-form-urlencoded", "Key": key, "Sign": sign}
url = 'https://www.ccedk.com/api/v1/' + method
response = json.loads(urllib2.urlopen(urllib2.Request(url, data, headers), timeout=15).read())
if response['errors'] is True:
response['error'] = ",".join(response['errors'].values())
return response
def cancel_orders(self, unit, side, key, secret):
response = self.post('order/list', {}, key, secret)
if not response['response'] or not response['response']['entities']:
return response
for order in response['response']['entities']:
if side == 'all' \
or (side == 'bid' and order['type'] == 'buy') \
or (side == 'ask' and order['type'] == 'sell'):
if order['pair_id'] == self.pair_id[unit.lower()]:
ret = self.post('order/cancel', {'order_id': order['order_id']}, key, secret)
if ret['errors'] is True:
if 'error' not in response:
response['error'] = ""
response['error'] += ",".join(ret['errors'].values())
return response
def place_order(self, unit, side, key, secret, amount, price):
params = {"type": 'buy' if side == 'bid' else 'sell',
"price": price,
"pair_id": int(self.pair_id[unit.lower()]),
"amount": amount}
response = self.post('order/new', params, key, secret)
if response['errors'] is True:
response['error'] = ",".join(response['errors'].values())
else:
response['id'] = int(response['response']['entity']['order_id'])
return response
def get_balance(self, unit, key, secret):
params = {"currency_id": self.currency_id[unit.lower()]}
response = self.post('balance/info', params, key, secret)
if response['errors'] is True:
response['error'] = ",".join(response['errors'].values())
else:
response['balance'] = float(response['response']['entity']['balance'])
return response
def get_price(self, unit):
url = 'https://www.ccedk.com/api/v1/orderbook/info?' + urllib.urlencode({'pair_id': self.pair_id[unit.lower()]})
response = json.loads(urllib2.urlopen(urllib2.Request(url), timeout=5).read())
if response['errors'] is True:
response['error'] = ",".join(response['errors'].values())
return response
response.update({'bid': None, 'ask': None})
if response['response']['entities']['bids']:
response['bid'] = float(response['response']['entities']['bids'][0]['price'])
if response['response']['entities']['asks']:
response['ask'] = float(response['response']['entities']['asks'][0]['price'])
return response
def create_request(self, unit, key=None, secret=None):
if not secret:
return None, None
request = {'nonce': self.nonce()}
data = urllib.urlencode(request)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
return request, sign
def validate_request(self, key, unit, data, sign):
headers = {"Content-type": "application/x-www-form-urlencoded", "Key": key, "Sign": sign}
url = 'https://www.ccedk.com/api/v1/order/list'
response = json.loads(urllib2.urlopen(urllib2.Request(url, urllib.urlencode(data), headers), timeout=5).read())
if response['errors'] is True:
response['error'] = ",".join(response['errors'].values())
return response
if not response['response']['entities']:
response['response']['entities'] = []
validation = [{
'id': int(order['order_id']),
'price': float(order['price']),
'type': 'ask' if order['type'] == 'sell' else 'bid',
'amount': float(order['volume']),
} for order in response['response']['entities'] if order['pair_id'] == self.pair_id[unit.lower()]]
return validation
class BitcoinCoId(Exchange):
def __init__(self):
super(BitcoinCoId, self).__init__(0.0)
try:
ping = time.time()
response = json.loads(urllib2.urlopen(urllib2.Request('https://vip.bitcoin.co.id/api/summaries')).read())
self._shift = float(response['tickers']['btc_idr']['server_time']) - ping
except:
pass
def __repr__(self):
return "bitcoincoid"
def adjust(self, error):
if "Nonce must be greater than" in error: # (TODO: regex)
if ':' in error: error = error.split(':')[1].strip()
error = error.replace('.', '').split()
self._shift += 100.0 + (int(error[5]) - int(error[8])) / 1000.0
else:
self._shift = self._shift + 100.0
def nonce(self, factor=1000.0):
n = int((time.time() + self._shift) * float(factor))
if n - self._nonce < 300:
n = self._nonce + 300
self._nonce = n
return n
def post(self, method, params, key, secret):
request = {'nonce': self.nonce(), 'method': method}
request.update(params)
data = urllib.urlencode(request)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
headers = {'Sign': sign, 'Key': key}
response = json.loads(urllib2.urlopen(urllib2.Request('https://vip.bitcoin.co.id/tapi', data, headers)).read())
return response
def cancel_orders(self, unit, side, key, secret):
response = self.post('openOrders', {'pair': 'nbt_' + unit.lower()}, key, secret)
if response['success'] == 0 or not response['return']['orders']: return response
for order in response['return']['orders']:
if side == 'all' or (side == 'bid' and order['type'] == 'buy') or (
side == 'ask' and order['type'] == 'sell'):
params = {'pair': 'nbt_' + unit.lower(), 'order_id': order['order_id'], 'type': order['type']}
ret = self.post('cancelOrder', params, key, secret)
if 'error' in ret:
if not 'error' in response: response['error'] = ""
response['error'] += "," + ret['error']
return response
def place_order(self, unit, side, key, secret, amount, price):
params = {'pair': 'nbt_' + unit.lower(), 'type': 'buy' if side == 'bid' else 'sell', 'price': price}
if side == 'bid':
params[unit.lower()] = amount * price
else:
params['nbt'] = amount
params[unit] = amount * price
response = self.post('trade', params, key, secret)
if response['success'] == 1:
response['id'] = int(response['return']['order_id'])
return response
def get_balance(self, unit, key, secret):
response = self.post('getInfo', {}, key, secret)
if response['success'] == 1:
response['balance'] = float(response['return']['balance'][unit.lower()])
return response
def get_price(self, unit):
response = json.loads(
urllib2.urlopen(urllib2.Request('https://vip.bitcoin.co.id/api/nbt_%s/depth' % unit.lower()),
timeout=5).read())
if 'error' in response:
return response
response.update({'bid': None, 'ask': None})
if response['buy']: response['bid'] = float(response['buy'][0][0])
if response['sell']: response['ask'] = float(response['sell'][0][0])
return response
def create_request(self, unit, key=None, secret=None):
if not secret: return None, None
request = {'nonce': self.nonce(), 'pair': 'nbt_' + unit.lower(), 'method': 'openOrders'}
data = urllib.urlencode(request)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
return request, sign
def validate_request(self, key, unit, data, sign):
headers = {"Key": key, "Sign": sign}
response = json.loads(
urllib2.urlopen(urllib2.Request('https://vip.bitcoin.co.id/tapi', urllib.urlencode(data), headers),
timeout=5).read())
if response['success'] == 0:
return response
if not response['return']['orders']:
response['return']['orders'] = []
return [{
'id': int(order['order_id']),
'price': float(order['price']),
'type': 'ask' if order['type'] == 'sell' else 'bid',
'amount': float(order['remain_' + (unit.lower() if order['type'] == 'buy' else 'nbt')]) / (
float(order['price']) if order['type'] == 'buy' else 1.0),
} for order in response['return']['orders']]
class BTER(Exchange):
def __init__(self):
super(BTER, self).__init__(0.002)
def __repr__(self):
return "bter"
def adjust(self, error):
pass
def https_request(self, method, params, headers=None, timeout=None):
if not headers: headers = {}
connection = httplib.HTTPSConnection('data.bter.com', timeout=timeout)
connection.request('POST', '/api/1/private/' + method, params, headers)
response = connection.getresponse().read()
return json.loads(response)
def post(self, method, params, key, secret):
data = urllib.urlencode(params)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
headers = {'Sign': sign, 'Key': key, "Content-type": "application/x-www-form-urlencoded"}
return self.https_request(method, data, headers)
def cancel_orders(self, unit, side, key, secret):
response = self.post('orderlist', {}, key, secret)
if not response['result']:
response['error'] = response['msg']
return response
if not response['orders']: response['orders'] = []
for order in response['orders']:
if side == 'all' or (side == 'ask' and order['sell_type'] != unit) or (
side == 'bid' and order['buy_type'] != unit):
if order['pair'] == 'nbt_' + unit.lower():
params = {'order_id': order['oid']}
ret = self.post('cancelorder', params, key, secret)
if not ret['result']:
if not 'error' in response: response['error'] = ""
response['error'] += "," + ret['msg']
return response
def place_order(self, unit, side, key, secret, amount, price):
params = {'pair': 'nbt_' + unit.lower(), 'type': 'buy' if side == 'bid' else 'sell', 'rate': price,
'amount': amount}
response = self.post('placeorder', params, key, secret)
if response['result']:
response['id'] = int(response['order_id'])
else:
response['error'] = response['msg']
return response
def get_balance(self, unit, key, secret):
response = self.post('getfunds', {}, key, secret)
if response['result']:
if unit.upper() in response['available_funds']:
response['balance'] = float(response['available_funds'][unit.upper()])
else:
response['balance'] = 0.0
else:
response['error'] = response['msg']
return response
def get_price(self, unit):
connection = httplib.HTTPSConnection('data.bter.com', timeout=5)
connection.request('GET', '/api/1/depth/nbt_' + unit.lower())
response = json.loads(connection.getresponse().read())
if not 'result' in response or not response['result']:
response['error'] = response['msg'] if 'msg' in response else 'invalid response: %s' % str(response)
return response
response.update({'bid': None, 'ask': None})
if response['bids']: response['bid'] = float(response['bids'][0][0])
if response['asks']: response['ask'] = float(response['asks'][-1][0])
return response
def create_request(self, unit, key=None, secret=None):
if not secret: return None, None
request = {} # no nonce required
data = urllib.urlencode(request)
sign = hmac.new(secret, data, hashlib.sha512).hexdigest()
return request, sign
def validate_request(self, key, unit, data, sign):
headers = {'Sign': sign, 'Key': key, "Content-type": "application/x-www-form-urlencoded"}
response = self.https_request('orderlist', urllib.urlencode(data), headers, timeout=15)
if not 'result' in response or not response['result']:
response['error'] = response['msg'] if 'msg' in response else 'invalid response: %s' % str(response)
return response
if not response['orders']:
response['orders'] = []
return [{
'id': int(order['oid']),
'price': float(order['rate']),
'type': 'ask' if order['buy_type'].lower() == unit.lower() else 'bid',
'amount': float(order['amount']) / (
1.0 if order['buy_type'].lower() == unit.lower() else float(order['rate'])),
} for order in response['orders'] if order['pair'] == 'nbt_' + unit.lower()]
class Peatio(Exchange):
def __init__(self):
super(Peatio, self).__init__(0.002)
def __repr__(self):
return "testing"
def adjust(self, error):
if "is invalid, current timestamp is" in error:
try:
tonce = int(error.split()[2])
times = int(error.split()[-1].replace('.', ''))
self._shift = int(float(times - tonce) / 1000.0)
except:
print error
pass
else:
print error
def urlencode(self, params): # from https://github.com/JohnnyZhao/peatio-client-python/blob/master/lib/auth.py#L11
keys = sorted(params.keys())
query = ''
for key in keys:
value = params[key]
if key != "orders":
query = "%s&%s=%s" % (query, key, value) if len(query) else "%s=%s" % (key, value)
else:
d = {key: params[key]}
for v in value:
ks = v.keys()
ks.sort()
for k in ks:
item = "orders[][%s]=%s" % (k, v[k])
query = "%s&%s" % (query, item) if len(query) else "%s" % item
return query
def query(self, qtype, method, params, key, secret):
request = {'tonce': self.nonce(), 'access_key': key}
request.update(params)
data = self.urlencode(request)
msg = "%s|/api/v2/%s|%s" % (qtype, method, data)
data += "&signature=" + hmac.new(secret, msg, hashlib.sha256).hexdigest()
connection = httplib.HTTPSConnection('178.62.140.24', timeout=5)
connection.request(qtype, '/api/v2/' + method + '?' + data)
return json.loads(connection.getresponse().read())
def post(self, method, params, key, secret):
return self.query('POST', method, params, key, secret)
def get(self, method, params, key, secret):
return self.query('GET', method, params, key, secret)
def cancel_orders(self, unit, side, key, secret):
response = self.get('orders.json', {'market': "nbt%s" % unit.lower()}, key, secret)
if 'error' in response:
response['error'] = response['error']['message']
return response
for order in response:
if side == 'all' or (side == 'bid' and order['side'] == 'buy') or (
side == 'ask' and order['side'] == 'sell'):
ret = self.post('order/delete.json', {'id': order['id']}, key, secret)
if 'error' in ret:
if isinstance(response, list): response = {'error': ""}
response['error'] += "," + ret['error']['message']
return response
def place_order(self, unit, side, key, secret, amount, price):
params = {'market': "nbt%s" % unit.lower(), "side": 'buy' if side == 'bid' else 'sell', "volume": amount,
"price": price}
response = self.post('orders', params, key, secret)
if 'error' in response:
response['error'] = response['error']['message']
else:
response['id'] = int(response['id'])
return response
def get_balance(self, unit, key, secret):
response = self.get('members/me.json', {}, key, secret)
if 'error' in response:
response['error'] = response['error']['message']
else:
response['balance'] = 0.0
for pair in response['accounts']:
if pair['currency'] == unit.lower():
response['balance'] = float(pair['balance'])
return response
def get_price(self, unit):
connection = httplib.HTTPSConnection('178.62.140.24', timeout=15)
connection.request('GET',
'/api/v2/depth.json?' + self.urlencode({'market': "nbt%s" % unit.lower(), 'limit': 1}))
response = json.loads(connection.getresponse().read())
if 'error' in response:
response['error'] = response['error']['message']
return response
response.update({'bid': None, 'ask': None})
if response['bids']: response['bid'] = float(response['bids'][0][0])
if response['asks']: response['ask'] = float(response['asks'][-1][0])
return response
def create_request(self, unit, key=None, secret=None):
if not secret: return None, None
request = {'tonce': self.nonce(), 'access_key': key, 'market': "nbt%s" % unit.lower()}
data = self.urlencode(request)
msg = "GET|/api/v2/orders.json|%s" % data
request['signature'] = hmac.new(secret, msg, hashlib.sha256).hexdigest()
return request, ''
def validate_request(self, key, unit, data, sign):
if not 'market' in data or data['market'] != "nbt%s" % unit.lower():
return {'error': 'invalid market'}
connection = httplib.HTTPSConnection('178.62.140.24', timeout=15)
connection.request('GET', '/api/v2/orders.json?' + self.urlencode(data))
response = json.loads(connection.getresponse().read())
if 'error' in response:
response['error'] = response['error']['message']
return response
return [{
'id': int(order['id']),
'price': float(order['price']),
'type': 'ask' if order['side'] == 'sell' else 'bid',
'amount': float(order['remaining_volume']),
} for order in response]