forked from YuSunwisc/freeman
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
jiaojinglong
committed
Nov 6, 2018
1 parent
c4cc868
commit ad5a282
Showing
2 changed files
with
360 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|