写在前面的话
这个小项目是笔者的一个面试题,作者之前在学习量化战略的时分,喜爱完成一些战略,许多并未安置到币安实盘,可是这个项目是安置到币安上的项目,确实给我带来了一些挑战,不过也从中学到了不少东西,先学了python异步编程,以及多线程.可能是由于作者的梯子设置有问题,所以没能真正运转起来,不过整体的逻辑完成了,由于网络的问题,没有进行调试,应该有许多事务上或许技术上的缺陷,可是我觉得跟着以后的进步,这些必定能够解决
自己关于量化交易很感兴趣,接到面试的时分,
我欣喜若狂,由于
我在想这会不会是一生中仅有的时机能够从事这个职业,
希望面试能够通过.
下面是我的项目解析
这儿是一些必要的库,和许多需要的大局变量
import asyncio
import logging
import json
import websocket
from threading import Thread
from binance.lib.utils import config_logging
from binance.error import ClientError
from binance.websocket.um_futures.websocket_client import UMFuturesWebsocketClient
from websocket_client import BinanceWebsocketClient
from binance.um_futures import UMFutures
config_logging(logging, logging.DEBUG)
api_key = "vwE11TOZU5IHxXuXu0nZ4eIrNHLl0Pr5kWw59yDIGm5pK7k6X0DvExohpyZI"
api_secret = "OYLN7mk6iC7ypnV5UgKJj2BlnmsCzFBA6txxxrCbyI5HF7Liri0DbKssN"#密钥现已经过修改
symbol = "ETHUSDT"
start_order_amount = 100.0
max_order_amount = 1000.0
total_order_amount = 50000.0
price_move_limit = 0.1
price_margin_percent = 0.01
cancel_range_percentage=0.001
stop_loss_rate=0.01
buy_orders = []
sell_orders = []
global um_futures_client
global current_price
这儿是止盈部分的代码,这儿我参阅了币安的文档,首要的逻辑是先获取账户信息,然后关于每一个仓位的盈利进行核算,然后进行止盈
async def stop_profit(current_price):
account_info = um_futures_client.account(recvWindow=6000)
positions = account_info['positions'][id]
for position in positions:
symbol = position['symbol']
position_size = float(position['positionAmt'])
unrealized_profit = float(position['unRealizedProfit'])
#关于每一个订单,只需盈利1%,那就能够平仓
if symbol == 'ETHUSDT' and position_size != 0:
# 核算订单盈利
profit_percent = (unrealized_profit /
(position_size * current_price)) * 100
if profit_percent >= 1.0 :#止盈
# 平仓
if position_size > 0:
await um_futures_client.new_order(
symbol=symbol,
side='SELL', # 平仓
type='MARKET',
quantity=abs(position_size)
)
else:
await um_futures_client.new_order(
symbol=symbol,
side='SELL', # 平仓
type='MARKET',
quantity=abs(position_size)
)
这儿是止损部分的代码,止损是全仓止损,核算全仓的亏本,然后关于所有的订单进行平仓
async def stop_loss():
#留意是全仓亏本,所以这儿的核算方式和止盈有所差别
account_info = um_futures_client.account(recvWindow=6000)#先获取账户信息
if account_info["totalUnrealizedProfit"]/account_info["totalInitialMargin"]>stop_loss_rate:
for position in positions:
if position_size > 0:
await um_futures_client.new_order(
symbol=symbol,
side='SELL', # 平仓
type='MARKET',
quantity=abs(position_size)
)
else:
await um_futures_client.new_order(
symbol=symbol,
side='SELL', # 平仓
type='MARKET',
quantity=abs(position_size)
)
这儿是安置订单的接口,要从初始化的客户端调用新订单的安置,这儿参阅了GitHub上面的样例
async def place_order(side, price, amount):
try:
response = um_futures_client.new_order(
symbol=symbol,
side=side,
type="LIMIT",
quantity=amount,
timeInForce="GTC",
price=price,
)
logging.info(response)
except ClientError as error:
logging.error("Found error. status: {}, error code: {}, error message: {}".format(
error.status_code, error.error_code, error.error_message
))
这儿是吊销订单的接口,同样参阅了github上面币安给的样例
async def cancel_orders(side, order_id):
try:
response = um_futures_client.cancel_order(
symbol=symbol, orderId=order_id, recvWindow=2000)
logging.info(response)
except ClientError as error:
logging.error("Found error. status: {}, error code: {}, error message: {}".format(
error.status_code, error.error_code, error.error_message
))
这儿是订单操控,用于完成上下一共一百个订单的完成,作者考虑这个函数花了许多的时间,可能还是有过错,可是应该基本上完善了,首要的逻辑便是把价格等分,然后上下价格设置订单,留意要把订单放在一个列表里面方便办理
sync def conduct_orders():
while True:
try:
scope = current_price * price_margin_percent
buy_price = current_price - scope
sell_price = current_price scope
# 更新50买单
for i in range(1, 51):
order_price = buy_price - (scope * (25 - i) / 25)
order_amount = start_order_amount
i * (total_order_amount / 50)
order_amount = min(order_amount, max_order_amount)
buy_orders.append((order_price, order_amount))
# 更新50卖单
for i in range(1, 51):
order_price = sell_price (scope * (i - 25) / 25)
order_amount = start_order_amount
(i - 25) * (total_order_amount / 50)
order_amount = min(order_amount, max_order_amount)
sell_orders.append((order_price, order_amount))
# 挂单
for order in buy_orders sell_orders:
# IO等候
await place_order("BUY" if order in buy_orders else "SELL", order[0], order[1])
await asyncio.sleep(1)
except Exception as e:
print(f"Error conduct_orders: {e}")
这儿也是十分核心的一段代码,目的是在什么情况下,进行订单的吊销,也便是行情动摇的时分进行订单的吊销,事务逻辑上稍微有点杂乱
async def delete_recent_orders():
while True:
try:
open_orders = await um_futures_client.get_open_orders("symbol",recvWindow=100)
if len(open_orders) > 0:
min_price = min(float(order["price"]) for order in open_orders)
max_price = max(float(order["price"]) for order in open_orders)
if max_price-min_price >= current_price*cancel_range_percentage:
# 吊销吊销千分之一范围内的订单
for order in open_orders:
if float(order["price"]) >= min_price and float(order["price"]) <= max_price:
# IO等候
await cancel_orders(order["side"], order["orderId"])#先撤单
await place_order(order["side"],order["price"],order['amount'])#再挂单
if max_price-min_price>=0.05*current_price:#我的了解是动摇百分之五在万分之五的下面,假如大于百分之五,那么一定大于万分之5行情剧烈动摇,假定为百分之五
#这时拉远最近的挂单间隔
if(order["side"]=="buy"):#假如是买单那就假定向上拉百分之10
await place_order(order["side"],order["price"]*1.1,order["amount"])
if(order["side"]=="sell"):#假如是卖单,那就假定向下拉百分之10
await place_order(order["side"],order["price"]*0.9,order["amount"])
except Exception as e:
print(f"ERROR delete_recent_orders{e}")
await asynio.sleep(1)
回调函数,可是没有用到,
这儿是一些回调函数,用于套接字的初始化,
def on_open():
data = {
"method": "SUBSCRIBE",
"params": [
"ethusdt@aggTrade",
"ethusdt@depth"
],
"id": 2
}
um_futures_client.send(data)
def on_close():
print('on close')
def message_handler(_, message):
print(message)
def on_error(error):
print(f"on error:{error}")
主函数的完成
作者在这一段纠结了好久到底该怎么样创建套接字websocket,试了许多方法,都无法链接url,可能是梯子的问题,也可能是自己关于websocket应用的不太娴熟
def target1():
print("线程1运转")
# socket = 'wss://fstream.binance.com/ws'
# base_url = socket '/ethusdt@trade'
# my_client = websocket.WebSocketApp(
# socket '/ethusdt@trade', on_open=on_open, on_message=message_handler, on_close=on_close)
my_client = UMFuturesWebsocketClient(
on_open=on_open,
on_close=on_close,
on_message=message_handler,
on_error=on_error
) # 这儿的url访问不了,我把梯子调成大局也不行
# 创建异步时间并运转
# my_client = BinanceWebsocketClient(
# base_url, on_open=on_open, on_close=on_close, on_error=on_error)
task = [conduct_orders(), delete_recent_orders()]
# 再写一个线程,进行平仓和止损的操作
# loop = asyncio.get_event_loop()
# loop.run_until_complete(asyncio.wait(task))py3.5
asyncio.run(task) # py3.7
def target2():
print("线程2运转")
task = [stop_profit(current_price),stop_loss()]
asyncio.run(task)
def main():
try:
um_futures_client = UMFutures(key=api_key, secret=api_secret)
current_price = um_futures_client.mark_price(symbol=symbol)
#这儿我认为,止盈止损应该贯穿整个市场行情中,假如单线程的话,可能会发生止盈止损不及时的情况所以我用了两个线程,一个线程用来办理订单,一个用来止盈和止损
t1=Thread(target=target1)
t2=Thread(target=target2)
t2.start()
t1.start()
#回收两个线程的资源
except Exception as e:
t1.join()
t2.join()
#这儿先发动止盈止损的线程,避免出现意外
if __name__ == '__main__':
main()