Skip to content

Commit

Permalink
增加下单交易demo和三角套利下单部分(未完成)
Browse files Browse the repository at this point in the history
  • Loading branch information
jiaojinglong committed Nov 6, 2018
1 parent c4cc868 commit ad5a282
Show file tree
Hide file tree
Showing 2 changed files with 360 additions and 0 deletions.
144 changes: 144 additions & 0 deletions code/study-trade.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import ccxt
import time
import os
import asyncio
import socket

# good_exchange_name = ['binance', 'fcoin', 'gateio', 'huobipro', 'kucoin', 'okex','bcex','bibox','bigone','bitfinex','bitforex',
# 'bithumb','bitkk','cex','coinbase','coinex','cointiger','exx','gdax','gemini','hitbtc','rightbtc',
# 'theocean','uex']
# good_exchange_name = ['kucoin', 'okex', 'bcex', 'bibox', 'bigone']
good_exchange_name = ['uex']
good_coin = ['ETH', 'XRP', 'BCH', 'EOS', 'XLM', 'LTC', 'ADA', 'XMR', 'TRX', 'BNB', 'ONT', 'NEO', 'DCR', 'LBA', 'RATING']

has_config_exchange = ['okex','uex']
config_key = dict()
config_key['okex'] = ['okex_key','okex_secret']
config_key['uex'] = ['uex_key','uex_secret']

# 订单交易量吃单比例
order_ratio = 0.5
# 价格滑点比例
slippage = 0.000

delay = 2


print('config_key is {}'.format(config_key))

def set_proxy():
os.environ.setdefault('http_proxy', 'http://127.0.0.1:1080')
os.environ.setdefault('https_proxy', 'http://127.0.0.1:1080')


# 获取指定交易所列表
def get_exchange_list(good_list):
exchange_list = []
for exchange_name in good_list:
exchange = getattr(ccxt,exchange_name)()
if exchange :
exchange_list.append(exchange)
return exchange_list


# 设置交易所key
def set_exchange_key(exchange):
if exchange.id in has_config_exchange:
exchange.apiKey = config_key[exchange.id][0]
exchange.secret = config_key[exchange.id][1]
print('set_exchange_key name is {},key is {},secret is {}'.format(exchange.name,exchange.apiKey,exchange.secret))
else:
print('set_exchange_key name is {} no key'.format(exchange.name))


def get_host_ip():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80))
ip = s.getsockname()[0]
finally:
s.close()
return ip

if __name__ == '__main__':

print('before proxy ip is {}'.format(get_host_ip()))
set_proxy()
print('after proxy ip is {}'.format(get_host_ip()))
good_exchange_list = get_exchange_list(good_exchange_name)
for exchange in good_exchange_list:
set_exchange_key(exchange)
for exchange in good_exchange_list:
print('exchange name is {},key is {},secret is {}'.format(exchange.name,exchange.apiKey,exchange.secret))
print('exchange has {}'.format(exchange.has))
try:
base = 'RATING'
quote = 'ETH'
symbol = base+'/'+quote
default_amount = 0.0001
default_price = 0
balance = exchange.fetch_balance()
orderbook = exchange.fetch_order_book(symbol)

buy_price = orderbook['bids'][0][0] if len (orderbook['bids']) > 0 else None
buy_amount = orderbook['bids'][0][1] if len(orderbook['bids']) > 0 else None
sell_price = orderbook['asks'][0][0] if len (orderbook['asks']) > 0 else None
sell_amount = orderbook['asks'][0][1] if len(orderbook['asks']) > 0 else None

quote_free = balance[quote]['free'] if balance[quote]['free'] else 0
quote_used = balance[quote]['used'] if balance[quote]['used'] else 0
quote_total = balance[quote]['total'] if balance[quote]['total'] else 0

base_free = balance[base]['free'] if balance[base]['free'] else 0
base_used = balance[base]['used'] if balance[base]['used'] else 0
base_total = balance[base]['total'] if balance[base]['total'] else 0

# 买操作
if quote_free > sell_price*sell_amount*order_ratio:
ret_buy = exchange.create_order(symbol,'limit','buy',sell_amount*order_ratio,sell_price*(1-slippage))
order = exchange.fetch_order(ret_buy['id'],symbol)
print('do buy ret_buy is {},order is {},amount {},filled {},remaining {}'.format(ret_buy,order,ret_buy['amount'],ret_buy['filled'],ret_buy['remaining']))
else:
print('do buy quote_free < sell_price*sell_amount InsufficientFunds {},{}'.format(quote_free,sell_price*sell_amount))

# 卖操作
if base_free >= buy_amount*order_ratio:
ret_sell = exchange.create_order(symbol, 'limit', 'sell', buy_amount*order_ratio, buy_price*(1+slippage))
order = exchange.fetch_order(ret_sell['id'],symbol)
print('do sell ret_sell is {},order is {},amount {},filled {},remaining {}'.format(ret_sell,order,ret_sell['amount'],ret_sell['filled'],ret_sell['remaining']))
else:
print('do sell base_free > buy_amount {},{}'.format(base_free,buy_amount))

# 卖
# if base_free > 0:
# ret_sell = exchange.create_order(symbol, 'limit', 'sell', base_free, buy_price*(1+slippage))
# order = exchange.fetch_order(ret_sell['id'],symbol)
# filled = order['filled']
# remaining = order['remaining']
# cost = order['cost']
# fee = order['fee']
# print('do sell ret_sell is {},order is {},amount {},filled {},remaining {}'.format(ret_sell,order,ret_sell['amount'],ret_sell['filled'],ret_sell['remaining']))
# print('order amount is {},filled is {},remaining is {},cost is {},fee is {}'.format(ret_sell['amount'],filled,remaining,cost,fee))
# else:
# print('do sell base_free > buy_amount {},{}'.format(base_free,buy_amount))

# 轮询3次取消尚未成交的订单
open_order_list = exchange.fetch_open_orders(symbol)
for open_order in open_order_list:
id = open_order['id']
retry = 0
while retry < 3:
if retry == 2:
exchange.cancel_order(id, symbol)
time.sleep(delay)
order = exchange.fetch_order(id, symbol)
filled = order['filled']
remaining = order['remaining']
amount = order['amount']
if filled/amount < order_ratio:
retry += 1
continue
#TODO 对冲操作

except Exception as e:
print('balance exception is {}'.format(e))
216 changes: 216 additions & 0 deletions code/triangle-trade.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import ccxt
import time
import os
"""
三角套利demo2:寻找三角套利空间,包含下单模块
交易对:用一种资产(quote currency)去定价另一种资产(base currency),比如用比特币(BTC)去定价莱特币(LTC),
就形成了一个LTC/BTC的交易对,
交易对的价格代表的是买入1单位的base currency(比如LTC)
需要支付多少单位的quote currency(比如BTC),
或者卖出一个单位的base currency(比如LTC)
可以获得多少单位的quote currency(比如BTC)。
中间资产mid currency可以是USDT等稳定币
"""
# P1 quote_mid BTC/USDT
# P2 base_mid LTC/USDT
# P3 base_quote LTC/BTC
default_base_cur = 'LTC'
default_quote_cur = 'BTC'
default_mid_cur = 'USDT'
# delay 2 second
delay = 2
# good_exchange_name = ['binance', 'fcoin', 'gateio', 'huobipro', 'kucoin', 'okex']
# good_exchange_name = ['binance', 'fcoin', 'gateio', 'huobipro', 'kucoin', 'okex','bcex','bibox','bigone','bitfinex','bitforex',
# 'bithumb','bitkk','cex','coinbase','coinex','cointiger','exx','gdax','gemini','hitbtc','rightbtc',
# 'theocean','uex']
# good_coin = ['ETH', 'XRP', 'BCH', 'EOS', 'XLM', 'LTC', 'ADA', 'XMR', 'TRX', 'BNB', 'ONT', 'NEO', 'DCR']

good_exchange_name = ['uex']
good_coin = ['ETH', 'XRP', 'BCH', 'EOS', 'XLM', 'LTC', 'ADA', 'XMR', 'TRX', 'BNB', 'ONT', 'NEO', 'DCR', 'LBA', 'RATING']

has_config_exchange = ['okex','uex']
config_key = dict()
config_key['okex'] = ['okex_key','okex_secret']
config_key['uex'] = ['uex_key','uex_secret']

# 订单交易量吃单比例
order_ratio = 0.5

def set_proxy():
os.environ.setdefault('http_proxy', 'http://127.0.0.1:1080')
os.environ.setdefault('https_proxy', 'http://127.0.0.1:1080')


# 获取指定交易所列表
def get_exchange_list(good_list):
exchange_list = []
for exchange_name in good_list:
exchange = getattr(ccxt,exchange_name)()
if exchange :
exchange_list.append(exchange)
return exchange_list


# 在指定交易所寻找三角套利机会,根据P3与P2/P1大小关系进行套利,暂不考虑滑点和手续费,目标保持base,quote数量不变,使mid数量增多
def find_trade_chance(exchange,base='LTC',quote='BTC',mid='USDT'):
try:
exchange.load_markets()
except Exception as e:
print('load_markets e is {} ,exchange is {}'.format(e.args[0],exchange.name))
return
cur_quote_mid = quote + '/' + mid
cur_base_mid = base+'/'+mid
cur_base_quote = base + '/' + quote

try:
book_quote_mid = exchange.fetch_order_book(cur_quote_mid)
time.sleep(delay)
book_base_mid = exchange.fetch_order_book(cur_base_mid)
time.sleep(delay)
book_base_quote = exchange.fetch_order_book(cur_base_quote)
except Exception as e:
print('fetch_order_book e is {} ,exchange is {}'.format(e.args[0],exchange.name))
return

# P1
price_quote_mid_bid1 = book_quote_mid['bids'][0][0] if len(book_quote_mid['bids']) > 0 else None
price_quote_mid_ask1 = book_quote_mid['asks'][0][0] if len(book_quote_mid['asks']) > 0 else None
size_quote_mid_bid1 = book_quote_mid['bids'][0][1] if len(book_quote_mid['bids']) > 0 else None
size_quote_mid_ask1 = book_quote_mid['asks'][0][1] if len(book_quote_mid['asks']) > 0 else None
# P2
price_base_mid_bid1 = book_base_mid['bids'][0][0] if len(book_base_mid['bids']) > 0 else None
price_base_mid_ask1 = book_base_mid['asks'][0][0] if len(book_base_mid['asks']) > 0 else None
size_base_mid_bid1 = book_base_mid['bids'][0][1] if len(book_base_mid['bids']) > 0 else None
size_base_mid_ask1 = book_base_mid['asks'][0][1] if len(book_base_mid['asks']) > 0 else None
# P3
price_base_quote_bid1 = book_base_quote['bids'][0][0] if len(book_base_quote['bids']) > 0 else None
price_base_quote_ask1 = book_base_quote['asks'][0][0] if len(book_base_quote['asks']) > 0 else None
size_base_quote_bid1 = book_base_quote['bids'][0][1] if len(book_base_quote['bids']) > 0 else None
size_base_quote_ask1 = book_base_quote['asks'][0][1] if len(book_base_quote['asks']) > 0 else None
date_time = exchange.last_response_headers['Date']
print('-----find_trade_chance开始在交易所{}寻找三角套利机会,base:{},quote:{},mid:{},time:{}'.format(exchange.name,base,quote,mid,date_time))
print('P1: buy1:{},{},sell1:{},{}'.format(price_quote_mid_bid1,size_quote_mid_bid1,price_quote_mid_ask1,size_quote_mid_ask1))
print('P2: buy1:{},{},sell1:{},{}'.format(price_base_mid_bid1, size_base_mid_bid1, price_base_mid_ask1,size_base_mid_ask1))
print('P3: buy1:{},{},sell1:{},{}'.format(price_base_quote_bid1, size_base_quote_bid1, price_base_quote_ask1,size_base_quote_ask1))
#检查正循环套利
'''
三角套利的基本思路是,用两个市场(比如BTC/CNY,LTC/CNY)的价格(分别记为P1,P2),
计算出一个公允的LTC/BTC价格(P2/P1),如果该公允价格跟实际的LTC/BTC市场价格(记为P3)不一致,
就产生了套利机会
P3<P2/P1
操作:买-卖/买
价格条件提交:base_quote_ask1卖1 < base_mid_bid1买1/quote_mid_ask1卖1
交易量Q3:三者中取最小下单量,单位要统一为P3交易对的个数
利润:Q3*P1*(P2/P1-P3)
'''
if price_base_quote_ask1 < price_base_mid_bid1/price_quote_mid_ask1:
trade_size = min(size_base_quote_ask1,size_base_mid_bid1,size_quote_mid_ask1/price_base_quote_ask1)
price_diff = price_quote_mid_ask1*(price_base_mid_bid1/price_quote_mid_ask1 - price_base_quote_ask1)
profit = trade_size*price_diff
print('++++++发现正套利机会 profit is {},price_diff is {},trade_size is {},P3: {} < P2/P1: {},time:{}\n\n'.format(
profit, price_diff,trade_size, price_base_quote_ask1, price_base_mid_bid1/price_quote_mid_ask1, date_time))
postive_trade(exchange,cur_base_quote,cur_base_mid,cur_quote_mid,size_base_quote_ask1,price_base_quote_ask1,
size_base_mid_bid1,price_base_mid_bid1,size_quote_mid_ask1,price_quote_mid_ask1)
# 检查逆循环套利
'''
P3>P2/P1
操作:卖-买/卖
价格条件:base_quote_bid1买1 > base_mid_ask1卖1/quote_mid_bid1买1
交易量Q3:三者中取最小下单量
利润:Q3*P1*(P3-P2/P1)
'''
elif price_base_quote_bid1 > price_base_mid_ask1/price_quote_mid_bid1:
trade_size = min(size_base_quote_bid1,size_base_mid_ask1,size_quote_mid_bid1/price_base_quote_bid1)
price_diff = price_quote_mid_bid1*(price_base_quote_bid1-price_base_mid_ask1/price_quote_mid_bid1)
profit = trade_size*price_diff
print('++++++发现逆套利机会 profit is {},price_diff is {},trade_size is {},P3: {} > P2/P1: {},time:{}\n\n'.format(
profit, price_diff, trade_size, price_base_quote_bid1, price_base_mid_ask1/price_quote_mid_bid1, date_time))
negative_trade()
else:
print('在交易所{}没有找到三角套利机会,time:{}\n\n'.format(exchange.name,date_time))


# 正循环套利
'''
正循环套利
正循环套利的顺序如下:
先去LTC/BTC吃单买入LTC,卖出BTC,然后根据LTC/BTC的成交量,使用多线程,
同时在LTC/CNY和BTC/CNY市场进行对冲。LTC/CNY市场吃单卖出LTC,BTC/CNY市场吃单买入BTC。
P3<P2/P1
操作:买-卖/买
'''


def postive_trade(exchange, base_quote, base_mid, quote_mid, size_base_quote_ask1, price_base_quote_ask1,
size_base_mid_bid1, price_base_mid_bid1, size_quote_mid_ask1, price_quote_mid_ask1):
#买入P3
result = exchange.create_order(base_quote, 'limit', 'buy', size_base_quote_ask1 * order_ratio,price_base_quote_ask1)

retry = 0
already_hedged_amount = 0
while retry < 3:
if retry == 2:
# cancel order
exchange.cancel_order(result['id'], base_quote)
break
order = exchange.fetch_order(result['id'], base_quote)
filled = order['filled']
remaining = order['remaining']
amount = order['amount']
if filled/amount < order_ratio:
retry +=1
continue
# 对冲卖P2
hedge_sell(exchange, base_mid, filled)
# 对冲买P1
hedge_buy(exchange, quote_mid, filled)

if filled >= amount:
break


'''
逆循环套利
逆循环套利的顺序如下:
先去LTC/BTC吃单卖出LTC,买入BTC,然后根据LTC/BTC的成交量,使用多线程,
同时在LTC/CNY和BTC/CNY市场进行对冲。
LTC/CNY市场吃单买入LTC,BTC/CNY市场吃单卖出BTC。
P3>P2/P1
操作:卖-买/卖
'''


# 逆循环套利
def negative_trade():
pass


# 对冲买
def hedge_sell(exchange, symbol, sell_size):
pass


# 对冲卖
def hedge_buy(exchange, symbol, buy_size):
pass


# 获取下单买入数量
def get_buy_size():
pass


# 获取下单卖出数量
def get_sell_size():
pass

if __name__ == '__main__':
set_proxy()
good_exchange_list = get_exchange_list(good_exchange_name)
# 在good_coin作为base,quote=BTC,mid=USDT 在good_exchange_list交易所列表中寻找套利机会
for symbol in good_coin:
for exchange in good_exchange_list:
find_trade_chance(exchange, symbol, default_quote_cur, default_mid_cur)

0 comments on commit ad5a282

Please sign in to comment.