写在前面的话

这个小项目是笔者的一个面试题,作者之前在学习量化战略的时分,喜爱完成一些战略,许多并未安置到币安实盘,可是这个项目是安置到币安上的项目,确实给我带来了一些挑战,不过也从中学到了不少东西,先学了python异步编程,以及多线程.可能是由于作者的梯子设置有问题,所以没能真正运转起来,不过整体的逻辑完成了,由于网络的问题,没有进行调试,应该有许多事务上或许技术上的缺陷,可是我觉得跟着以后的进步,这些必定能够解决

自己关于量化交易很感兴趣,接到面试的时分,

我欣喜若狂,由于

我在想这会不会是一生中仅有的时机能够从事这个职业,

希望面试能够通过.

下面是我的项目解析

币安挂单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

这儿是止盈部分的代码,这儿我参阅了币安的文档,首要的逻辑是先获取账户信息,然后关于每一个仓位的盈利进行核算,然后进行止盈

币安挂单python完成

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上面的样例

币安挂单python完成

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()