从零开始学Python编写量化交易机器人:实现加密货币实盘交易,附交易源码(二)

技术博客1年前 (2023)更新 Dexnav
0

从零开始学Python编写量化交易机器人:实现加密货币实盘交易 (二)

 

作者: Dexnav    代开发量化交易机器人请电报联系:  dexdao
加入生财有道社群: scyd_dao
 
欢迎回来!在上一章中,我们详细介绍了如何从零开始使用Python编写量化交易机器人,并讲解了量化基础概念和Python安装和交易模型。在这一章,我们将深入探讨实盘交易的具体案例,包括模拟交易平台的介绍、数据获取和处理、机器学习模型的测试和优化以及实盘交易的结果和总结。通过这些实际案例的演示,读者可以更加深入地了解量化交易的应用和实践,以及如何运用Python编写高效的量化交易机器人。
如果你还没有看过上一章节请查看: 从零开始学Python编写量化交易机器人:实现加密货币实盘交易 (一)
分享的这个策略是我在学习量化交易后尝试编写的主要策略,它基于均值回归的思想,使用Python语言和相关的库和工具实现,目前仅为简化版本,仅供参考。这个策略没有仓位管理,每次交易都是满仓,并没有卡死后重启等功能。但是,这个策略已经在历史数据上进行了回测,并且表现良好,没有明显的缺陷。该策略的运行时间从2015年1月至今,回报率表现良好。
从零开始学Python编写量化交易机器人:实现加密货币实盘交易,附交易源码(二)
为什么分享这个策略

  1. 希望能够帮助更多的投资者了解和学习量化交易,尤其是在加密货币交易市场中的应用。
  2. 对于已经在量化交易领域中工作或研究的专业人士,这个策略也可以作为一个参考案例,帮助他们更好地改进和优化自己的策略。
  3. 作为一个交流学习的机会,可以与其他投资者和交易者分享自己的经验和见解,共同进步。该策略的原理非常简单,可以理解为一种类似于做市商的准高频策略。当时几乎谁都能写出来,但其效果非常有效。在2014年,比特币机器人初兴之时,编写一种赚钱的策略非常容易。与所有高频交易策略一样,该策略基于订单簿。下图展示了一个典型的比特币交易所的订单簿分布情况:从零开始学Python编写量化交易机器人:实现加密货币实盘交易,附交易源码(二)策略的基本思路是不断进行买入卖出操作,以获取订单簿的价差利润。在这个策略中,我们使用一个参数来决定买入和卖出的价格,该参数的值取决于订单簿中的最低卖价和最高买价。如果最低卖价高于最高买价,则进行卖出操作;否则进行买入操作。通过这种方式,我们可以获得订单簿的价差利润。

如果一个人要买入比特币,如果不想挂单等待,只能选择吃单,如果他的单子比较多,会使得卖单挂单大量成交,对价格造成冲击,但这种冲击一般不会持续太久,还有人想吃单卖出,价格在极短时间很可能会恢复,反过来理解有人要卖币也类似。以图中的挂单为例,如果要直接买入5个币,那么价格会达到10377,在这时如果有人要直接卖出5个币,价格会达到10348,这个空间就是利润空间。策略会在稍低于10377的价格挂单,如10376.99,同时会以稍高于10348的价格买入,如10348.01,这是如果刚才的情况发生了,显然就会赚到其中的差价。虽然不会每次都如此完美,但在概率的作用下,赚钱的几率实际上非常高。

以现在策略的参数讲解一下具体操作。首先向上寻找累计卖挂单量为8个币的价格,这里是10377,那么此时的卖价就是这个价格减去0.01(减去多少可以是随机的)。同理,向下寻找累计买挂单为8个币,这里是10348,那么此时的买价就是10348.01。此时买卖价的差价是10376.99-10348.01=28.98,大于策略预设的差价1.5,就以这两个价格挂单等待成交。如果价差小于1.5,也会找一个价格进行挂单,如盘口价格加减10,等待捡漏。在这个策略中,没有仓位管理,每次交易都是满仓的状态。

虽然该策略非常简单,但其效果却非常有效。在实际应用中,我们可以使用机器学习等方法对其进行进一步优化,以提高其效率和稳定性。

没有Token怎么办? 在账户Token不足时,通常只能选择单边挂单等待成交,但这并不是大问题。虽然可以加入资金平衡的逻辑,但在平衡的过程中难免会产生损失,因为每次成交都是概率性的。因此,我选择继续单边等待成交,尽管这样也浪费了另一边的成交机会。 如何管理仓位? 一开始都是满仓买入卖出,后来根据不同的参数分为不同的组,不会一次完全成交。 有止损吗? 该策略的买卖挂单逻辑是完整的,因此我认为没有必要设置止损(虽然可以进行讨论)。此外,概率也是一个重要的考虑因素,每次成交都是一次机会,设置止损反而会浪费这种机会。 如何调整为赚币策略? 此时的参数是对称的,即向上8个币的累计卖单和向下8个币的累计买单。如果想要调整为赚币的策略,可以稍微调整一下参数,比如将向上的卖单改为15个币,这样就更难以出售币,从而有更大的几率以更低的价格将币买回来,从而实现赚币的目的。反之,调整向下的买单可以实现赚钱的策略。事实上,在前期该策略非常有效,因为币和钱都在增加。

完整的代码可以在我分享的策略中查看,这里只讲解核心逻辑函数。在没有进行改动的情况下,该策略竟然可以在BotVS自带的模拟盘中完全正常运行,这是一个3年多前的策略,现在平台仍然支持,这真的很让人感动。 首先是获取买卖价的函数GetPrice(),它需要获取订单深度信息。需要注意不同平台的订单深度信息长度不同,以及即使遍历了所有订单仍然没有所需要的量的情况(在后期许多0.01的网格挂单会导致这种情况)。调用GetPrice(‘Buy’)就是获取买价的价格

这里是获取买卖价的核心函数GetPrice(),需要获取订单深度信息,并计算买价和卖价。注意不同平台的订单深度信息长度不同,以及即使遍历了所有订单仍然没有所需要的量的情况。调用是GetPrice(‘Buy’)就是获取买价。

def GetPrice(Type):
    # 获取订单深度信息
    depth = exchange.GetDepth()
    amount_bids = 0
    amount_asks = 0
    # 计算买价,获取累计深度达到预设的价格
    if Type == "Buy":
        for i in range(20):
            amount_bids += depth.Bids[i].Amount
            # 参数floatamountbuy是预设的累计深度
            if amount_bids > floatamountbuy:
                # 稍微加0.01,使得订单排在前面
                return depth.Bids[i].Price + 0.01
    # 同理计算卖价
    if Type == "Sell":
        for j in range(20):
            amount_asks += depth.Asks[j].Amount
            if amount_asks > floatamountsell:
                return depth.Asks[j].Price - 0.01
    # 遍历了全部深度仍未满足需求,就返回一个价格,以免出现bug
    return depth.Asks[0].Price

下面是每个循环的主函数onTick(),在这里设置循环时间为3.5秒。每次循环都会先撤销之前的所有挂单,然后重新挂单。这样做的好处是简单易行,减少出错的概率。

function onTick() {
var buyPrice = GetPrice("Buy");
var sellPrice= GetPrice("Sell");
//如果买卖价差小于预设差价,就挂一个相对更深的价格
if ((sellPrice - buyPrice) <= diffprice){
buyPrice-=10;
sellPrice+=10;}
//撤销所有未完成的订单
CancelPendingOrders()
//获取账户信息,确定账户中现有多少钱和币
var account=_C(exchange.GetAccount);
//计算可买币的数量
var amountBuy = _N((account.Balance / buyPrice-0.1),2);
//计算可卖币的数量,没有仓位的限制
var amountSell = _N((account.Stocks),2);
//如果可卖币的数量大于0.02,就挂卖单
if (amountSell > 0.02) {
exchange.Sell(sellPrice,amountSell);}
//如果可买币的数量大于0.02,就挂买单
if (amountBuy > 0.02) {
exchange.Buy(buyPrice, amountBuy);}
//休眠一段时间后进入下一轮循环
Sleep(sleeptime);
}

结尾

整个程序只有40多行,看起来非常简单,但当时我花了一个多星期的时间才完成它,而且还是在botvs平台上完成的。它的最大优势在于,它起步早,在2014年,市场上主要是搬砖交易,网格和抢盘口的高频交易也不多,这让我的策略非常适应市场。但随着竞争的加剧,我的交易资金也越来越多,我面临的挑战也越来越多,每隔一段时间就需要进行较大的改动以适应市场。但总的来说,这一过程还算顺利。在交易平台不收取手续费的情况下,它是程序化交易的天堂。散户因为不收手续费而趋向于进行操作,这为高频交易和套利交易提供了空间,这一切也基本上随着0.1-0.2%的双向手续费的普及而结束了。这不仅仅是自己被收费的问题,而是整个市场活跃度下降。但是,不需要高频交易的量化策略仍然有很大的空间。

策略源码

/*
这是我最初编写的机器人代码,几乎没有改动,参数也与原版相同。
虽然有许多需要改进的地方,但即使如此,它当时表现出惊人的盈利能力,特别是在我刚开始时资金不多的情况下,平均每天的收益率在5%左右。当然,无论从哪个方面看,这种策略都无法适应今天的市场。
我同时也在平台发表了一篇文章,大家可以看看。
by DexNav
*/

//使用平台的容错函数_C()和精度函数_N()
//取消所有挂单
function CancelPendingOrders() {
var orders = _C(exchange.GetOrders);
for (var j = 0; j < orders.length; j++) {
exchange.CancelOrder(orders[j].Id, orders[j]);
}
}

//计算将要下单的价格
function GetPrice(Type, depth) {
var amountBids = 0;
var amountAsks = 0;
//计算买价,获取累计深度达到预设的价格
if (Type == "Buy") {
for (var i = 0; i < 20; i++) {
amountBids += depth.Bids[i].Amount;
//floatamountbuy就是预设的累计买单深度
if (amountBids > floatamountbuy) {
//稍微加0.01,使得订单排在前面
return depth.Bids[i].Price + 0.01;
}
}
}
//同理计算卖价
if (Type == "Sell") {
for (var j = 0; j < 20; j++) {
amountAsks += depth.Asks[j].Amount;
if (amountAsks > floatamountsell) {
return depth.Asks[j].Price - 0.01;
}
}
}
//遍历了全部深度仍未满足需求,就返回一个价格,以免出现bug
return depth.Asks[0].Price;
}

function onTick() {
var depth = _C(exchange.GetDepth);
var buyPrice = GetPrice("Buy", depth);
var sellPrice = GetPrice("Sell", depth);
//买卖价差如果小于预设值diffprice,就会挂一个相对更深的价格
if ((sellPrice - buyPrice) <= diffprice) {
buyPrice -= 10;
sellPrice += 10;
}
//撤销所有已挂单,实际上经常会出现新价格与已挂单价格相同的情况,此时不需要撤销
CancelPendingOrders();
//获取账户信息,确定账户目前拥有多少钱和多少币
var account = _C(exchange.GetAccount);
//可买的比特币量
var amountBuy = _N((account.Balance / buyPrice - 0.1), 2);
//可卖的比特币量,没有仓位限制,有多少就买

 

© 版权声明

相关文章

暂无评论

暂无评论...