与纽约证券交易所等具有固定交易时间的传统证券交易所不同,加密货币是 24/7 全天候交易的,这使得任何人都不可能独自监控市场。
过去,我经常需要处理与我的加密货币交易相关的以下问题:
- 隔夜发生了什么?
- 为什么没有日志条目?
- 为什么下了这个订单?
- 为什么没有下单?
通常的解决方案是使用加密货币交易机器人,当你在做其他事情时,比如睡觉、陪伴家人或享受空闲时间,它可以为你下单。有很多商业解决方案可用,但我想要一个开源选项,所以我创建了加密货币交易机器人 Pythonic。正如 我在去年的一篇介绍性文章中写道,“Pythonic 是一款图形化编程工具,使用户能够通过现成的功能模块轻松创建 Python 应用程序。”它最初是一个加密货币机器人,并具有广泛的日志记录引擎和经过良好测试的可重用部件,例如调度器和定时器。
入门指南
本实践<0xC2><0xA0>教程将教你如何开始使用 Pythonic 进行自动化交易。它以在 Binance 交易所平台上交易 Tron 对 Bitcoin 为例。我选择这些币种是因为它们彼此之间的波动性,而不是任何个人偏好。
该机器人将根据 指数移动平均线 (EMA) 做出决策。

TRX/BTC 1 小时蜡烛图
EMA 指标通常是一个加权移动平均线,它赋予最近的价格数据更多的权重。虽然移动平均线可能是一个简单的指标,但我使用它获得了良好的经验。
上图中的紫色线显示了 EMA-25 指标(意味着考虑了最近 25 个值)。
机器人监控当前 EMA-25 值 (t0) 和前一个 EMA-25 值 (t-1) 之间的斜率。如果斜率超过某个值,则表示价格上涨,机器人将下买单。如果斜率低于某个值,机器人将下卖单。
斜率将是做出交易决策的主要指标。在本教程中,它将被称为交易因子。
工具链
本教程中使用以下工具:
- Binance 专业交易视图(可视化<0xC2><0xA0>数据已被许多其他人完成,因此无需重复造轮子自己完成)
- 用于数据科学任务的 Jupyter Notebook
- Pythonic,它是<0xC2><0xA0>整体框架
- PythonicDaemon 作为<0xC2><0xA0>纯运行时(仅限控制台和 Linux)
数据挖掘
为了让加密货币交易机器人做出好的决策,可靠地获取你的资产的开盘价-最高价-最低价-收盘价 (OHLC) 数据至关重要。你可以使用 Pythonic 的内置元素并用你自己的逻辑扩展它们。
一般工作流程是:
- 与 Binance 时间同步
- 下载 OHLC 数据
- 将现有的 OHLC 数据从文件加载到内存中
- 比较两个数据集,并用较新的行扩展现有数据集
这个工作流程可能有点过分,但它使该解决方案非常可靠,可以抵抗停机时间和断开连接。
首先,你需要 Binance OHLC 查询元素和一个 基本操作 元素来执行你自己的代码。

数据挖掘工作流程
OHLC 查询设置为查询资产对 TRXBTC (Tron/Bitcoin) 的一小时间隔数据。

配置 OHLC 查询元素
此元素的输出是一个 Pandas DataFrame。你可以使用 基本操作 元素中的 input 变量访问 DataFrame。在这里,基本操作 元素设置为使用 Vim 作为默认代码编辑器。

基本操作元素设置为使用 Vim
以下是代码的样子:
import pickle, pathlib, os
import pandas as pd
outout = None
if isinstance(input, pd.DataFrame):
file_name = 'TRXBTC_1h.bin'
home_path = str(pathlib.Path.home())
data_path = os.path.join(home_path, file_name)
try:
df = pickle.load(open(data_path, 'rb'))
n_row_cnt = df.shape[0]
df = pd.concat([df,input], ignore_index=True).drop_duplicates(['close_time'])
df.reset_index(drop=True, inplace=True)
n_new_rows = df.shape[0] - n_row_cnt
log_txt = '{}: {} new rows written'.format(file_name, n_new_rows)
except:
log_txt = 'File error - writing new one: {}'.format(e)
df = input
pickle.dump(df, open(data_path, "wb" ))
output = df
首先,检查输入是否为 DataFrame 类型。然后在用户的主目录 (~/) 中查找名为 TRXBTC_1h.bin 的文件。如果存在,则打开它,连接新行(try 部分中的代码),并删除重叠的重复项。如果该文件不存在,则触发一个异常并执行 except 部分中的代码,创建一个新文件。
只要启用 log output 复选框,你就可以使用命令行工具 tail 跟踪日志记录。
$ tail -f ~/Pythonic_2020/Feb/log_2020_02_19.txt
为了开发目的,现在跳过与 Binance 时间的同步和定期调度。这将在下面实现。
数据准备
下一步是在单独的网格中处理评估逻辑;因此,你必须借助 返回元素 将 DataFrame 从网格 1 传递到网格 2 的第一个元素。
在网格 2 中,通过将 DataFrame 传递到 基本技术分析 元素,用包含 EMA 值的列扩展 DataFrame。

配置技术分析元素以计算周期为 25 个值的 EMA。

配置<0xC2><0xA0>技术分析元素
当你运行整个设置并激活 技术分析 元素的调试输出时,你会意识到 EMA-25 列的值似乎都相同。

这是因为调试输出中的 EMA-25 值仅包含六位小数,即使输出保留了 8 字节浮点值的完整精度。
为了进一步处理,添加一个 基本操作 元素

网格 2 中的工作流程
使用 基本操作 元素,转储具有附加 EMA-25 列的 DataFrame,以便可以将其加载到 Jupyter Notebook 中;

将扩展的 DataFrame 转储到文件
评估逻辑
在 Juypter Notebook 中开发评估逻辑使你能够以更直接的方式访问代码。要加载 DataFrame,你需要以下几行:

以所有小数位表示
你可以使用 iloc 和列名访问最新的 EMA-25 值。这保留了所有的小数位。
你已经知道如何获取最新值。上面的示例的最后一行仅显示该值。要将该值复制到单独的变量,你必须使用 .at 方法访问它,如下所示。
你还可以直接计算交易因子,你将在下一步中需要它。

确定交易因子
正如你在上面的代码中看到的,我选择 0.009 作为交易因子。但我如何知道 0.009 是否是用于决策的良好交易因子?实际上,这个因子非常糟糕,因此你可以改为暴力破解性能最佳的交易因子。
假设你将根据收盘价买入或卖出。

在本示例中,buy_factor 和 sell_factor 是预定义的。因此,扩展逻辑以暴力破解性能最佳的值。

用于确定买入和卖出因子的嵌套 for 循环
这有 81 个循环要处理 (9x9),在我的机器(Core i7 267QM)上需要几分钟。

暴力破解时的系统利用率
在每个循环之后,它将 buy_factor、sell_factor 和结果 profit 的元组附加到 trading_factors 列表中。按利润降序排列列表。

按利润降序排列具有相关交易因子的利润
当你打印列表时,你可以看到 0.002 是最有希望的因子。

当我在 2020 年 3 月写这篇文章时,价格波动不够大,无法呈现更有希望的结果。我在 2 月份获得了更好的结果,但即使在那时,表现最佳的交易因子也在 0.002 左右。
拆分执行路径
现在启动一个新的网格以保持清晰。使用 返回 元素将具有 EMA-25 列的 DataFrame 从网格 2 传递到网格 3 的元素 0A。
在网格 3 中,添加一个 基本操作 元素来执行评估逻辑。这是该元素的代码:

该元素输出 1(如果你应该买入)或 -1(如果你应该卖出)。输出 0 表示现在无事可做。使用 分支 元素来控制执行路径。

由于 0 和 -1 的处理方式相同,因此你需要在最右侧的执行路径上添加一个额外的分支元素,以决定是否应该卖出。

网格 3 现在应该看起来像这样:

执行订单
由于你不能买入两次,因此你必须在周期之间保留一个持久变量,指示你是否已经买入。
你可以使用 堆栈元素 来做到这一点。顾名思义,堆栈元素是基于文件的堆栈的表示,可以填充任何 Python 数据类型。
你需要定义堆栈仅包含一个布尔元素,该元素确定你是否已买入(True)或未买入(False)。因此,你必须用一个 False 预设堆栈。例如,你可以在网格 4 中通过简单地将 False 传递到堆栈来设置它。

分支树之后的堆栈实例可以配置如下:

配置堆栈元素
在堆栈元素配置中,将 对输入执行此操作 设置为 无操作。否则,布尔值将被 1 或 0 覆盖。
此配置确保堆栈中始终只保存一个值(True 或 False),并且始终只能读取一个值(为了清晰起见)。
紧接在堆栈元素之后,你需要一个额外的 分支 元素来评估堆栈值,然后再放置 Binance 订单 元素。

评估<0xC2><0xA0>来自堆栈的变量
将 Binance 订单元素附加到分支元素的 True 路径。网格 3 上的工作流程现在应该看起来像这样:

Binance 订单元素配置如下:

配置<0xC2><0xA0>Binance 订单元素
你可以在 Binance 网站上的帐户设置下生成 API 密钥和密钥。

在 Binance 帐户设置中创建 API 密钥
在本教程中,每笔交易都作为市价单执行,交易量为 10,000 TRX(2020 年 3 月约为 150 美元)。(为了本教程的目的,我正在演示使用市价单的整个过程。因此,我建议至少使用限价单。)
如果订单未正确执行(例如,连接问题、资金不足或错误的货币对),则不会触发后续元素。因此,你可以假设如果触发了后续元素,则订单已下达。
以下是来自 XMRBTC 的成功卖单输出示例:

成功卖单
此行为使后续步骤更加舒适:你可以始终假设只要输出正确,订单就已下达。因此,你可以附加一个 基本操作 元素,该元素只需将输出写入 True 并将此值写入堆栈,以指示订单是否已下达。
如果出现问题,你可以在日志消息中找到详细信息(如果启用了日志记录)。

来自<0xC2><0xA0>Binance 订单元素的日志输出
计划和同步
对于定期调度和同步,请在网格 1 中的整个工作流程前面加上 Binance 调度器 元素。

网格 1 中位置 1A 的 Binance 调度器
Binance 调度器元素仅执行一次,因此在网格 1 的末尾拆分执行路径,并通过将输出传递回 Binance 调度器元素来强制其重新同步自身。

元素 5A 指向网格 2 的元素 1A,元素 5B 指向网格 1 的元素 1A(Binance 调度器)。
部署
你可以在本地机器上 24/7 全天候运行整个设置,或者你可以将其完全托管在廉价的云系统上。例如,你可以使用 Linux/FreeBSD 云系统,每月约 5 美元,但它们通常不提供窗口系统。如果你想利用这些低成本云,你可以使用 PythonicDaemon,它完全在终端内部运行。

PythonicDaemon 控制台
PythonicDaemon 是基本安装的一部分。要使用它,请保存你的完整工作流程,将其传输到远程运行系统(例如,通过安全复制 [SCP]),并使用工作流程文件作为参数启动 PythonicDaemon
$ PythonicDaemon trading_bot_one
要在系统启动时自动启动 PythonicDaemon,你可以向 crontab 添加一个条目
# crontab -e

下一步
正如我在开头写的那样,本教程只是自动化交易的起点。编程交易机器人大约是 10% 的编程和 90% 的测试。当涉及到让你的机器人用你的钱进行交易时,你肯定会对你编程的代码三思而后行。因此,我建议你尽可能保持代码简单易懂。
如果你想继续自己开发你的交易机器人,接下来要设置的是:
- 自动利润计算(希望只有正数!)
- 计算你想买入的价格
- 与你的订单簿进行比较(即,订单是否已完全成交?)
你可以在 GitHub 上下载整个示例。
4 条评论