如何使用 Python 自动化你的加密货币交易

在本教程中,学习如何设置和使用 Pythonic,这是一款图形化编程工具,使用户能够通过现成的功能模块轻松创建 Python 应用程序。
163 位读者喜欢这篇文章。

与纽约证券交易所等具有固定交易时间的传统证券交易所不同,加密货币是 24/7 全天候交易的,这使得任何人都不可能独自监控市场。

过去,我经常需要处理与我的加密货币交易相关的以下问题:

  • 隔夜发生了什么?
  • 为什么没有日志条目?
  • 为什么下了这个订单?
  • 为什么没有下单?

通常的解决方案是使用加密货币交易机器人,当你在做其他事情时,比如睡觉、陪伴家人或享受空闲时间,它可以为你下单。有很多商业解决方案可用,但我想要一个开源选项,所以我创建了加密货币交易机器人 Pythonic。正如 我在去年的一篇介绍性文章中写道,“Pythonic 是一款图形化编程工具,使用户能够通过现成的功能模块轻松创建 Python 应用程序。”它最初是一个加密货币机器人,并具有广泛的日志记录引擎和经过良好测试的可重用部件,例如调度器和定时器。

入门指南

本实践<0xC2><0xA0>教程将教你如何开始使用 Pythonic 进行自动化交易。它以在 Binance 交易所平台上交易 TronBitcoin 为例。我选择这些币种是因为它们彼此之间的波动性,而不是任何个人偏好。

该机器人将根据 指数移动平均线 (EMA) 做出决策。

TRX/BTC 1-hour candle chart

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 的内置元素并用你自己的逻辑扩展它们。

一般工作流程是:

  1. 与 Binance 时间同步
  2. 下载 OHLC 数据
  3. 将现有的 OHLC 数据从文件加载到内存中
  4. 比较两个数据集,并用较新的行扩展现有数据集

这个工作流程可能有点过分,但它使该解决方案非常可靠,可以抵抗停机时间和断开连接。

首先,你需要 Binance OHLC 查询元素和一个 基本操作 元素来执行你自己的代码。

Data-mining workflow

数据挖掘工作流程

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

Configuration of the OHLC query element

配置 OHLC 查询元素

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

Basic Operation element set up to use 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。

Technical analysis workflow in Grid 2

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

Configuration of the technical analysis element

配置<0xC2><0xA0>技术分析元素

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

Missing decimal places in output

这是因为调试输出中的 EMA-25 值仅包含六位小数,即使输出保留了 8 字节浮点值的完整精度。

为了进一步处理,添加一个 基本操作 元素

Workflow in Grid 2

网格 2 中的工作流程

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

Dump extended DataFrame to file

将扩展的 DataFrame 转储到文件

评估逻辑

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

Representation with all decimal places

以所有小数位表示

你可以使用 iloc 和列名访问最新的 EMA-25 值。这保留了所有的小数位。

你已经知道如何获取最新值。上面的示例的最后一行仅显示该值。要将该值复制到单独的变量,你必须使用 .at 方法访问它,如下所示。

你还可以直接计算交易因子,你将在下一步中需要它。

Buy/sell decision

确定交易因子

正如你在上面的代码中看到的,我选择 0.009 作为交易因子。但我如何知道 0.009 是否是用于决策的良好交易因子?实际上,这个因子非常糟糕,因此你可以改为暴力破解性能最佳的交易因子。

假设你将根据收盘价买入或卖出。

Validation function

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

Nested for loops for determining the buy and sell factor

用于确定买入和卖出因子的嵌套 for 循环

这有 81 个循环要处理 (9x9),在我的机器(Core i7 267QM)上需要几分钟。

System utilization while brute forcing

暴力破解时的系统利用率

在每个循环之后,它将 buy_factorsell_factor 和结果 profit 的元组附加到 trading_factors 列表中。按利润降序排列列表。

Sort profit with related trading factors in descending order

按利润降序排列具有相关交易因子的利润

当你打印列表时,你可以看到 0.002 是最有希望的因子。

Sorted list of trading factors and profit

当我在 2020 年 3 月写这篇文章时,价格波动不够大,无法呈现更有希望的结果。我在 2 月份获得了更好的结果,但即使在那时,表现最佳的交易因子也在 0.002 左右。

拆分执行路径

现在启动一个新的网格以保持清晰。使用 返回 元素将具有 EMA-25 列的 DataFrame 从网格 2 传递到网格 3 的元素 0A。

在网格 3 中,添加一个 基本操作 元素来执行评估逻辑。这是该元素的代码:

Implemented evaluation logic

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

Branch element: Grid 3 Position 2A

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

Branch element: Grid 3 Position 3B

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

Workflow on Grid 3

执行订单

由于你不能买入两次,因此你必须在周期之间保留一个持久变量,指示你是否已经买入。

你可以使用 堆栈元素 来做到这一点。顾名思义,堆栈元素是基于文件的堆栈的表示,可以填充任何 Python 数据类型。

你需要定义堆栈仅包含一个布尔元素,该元素确定你是否已买入(True)或未买入(False)。因此,你必须用一个 False 预设堆栈。例如,你可以在网格 4 中通过简单地将 False 传递到堆栈来设置它。

Forward a False-variable to the subsequent Stack element

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

Configuration of the Stack element

配置堆栈元素

在堆栈元素配置中,将 对输入执行此操作 设置为 无操作。否则,布尔值将被 1 或 0 覆盖。

此配置确保堆栈中始终只保存一个值(TrueFalse),并且始终只能读取一个值(为了清晰起见)。

紧接在堆栈元素之后,你需要一个额外的 分支 元素来评估堆栈值,然后再放置 Binance 订单 元素。

Evaluate the variable from the stack

评估<0xC2><0xA0>来自堆栈的变量

将 Binance 订单元素附加到分支元素的 True 路径。网格 3 上的工作流程现在应该看起来像这样:

Workflow on Grid 3

Binance 订单元素配置如下:

Configuration of the Binance Order element

配置<0xC2><0xA0>Binance 订单元素

你可以在 Binance 网站上的帐户设置下生成 API 密钥和密钥。

Creating an API key in Binance

在 Binance 帐户设置中创建 API 密钥

在本教程中,每笔交易都作为市价单执行,交易量为 10,000 TRX(2020 年 3 月约为 150 美元)。(为了本教程的目的,我正在演示使用市价单的整个过程。因此,我建议至少使用限价单。)

如果订单未正确执行(例如,连接问题、资金不足或错误的货币对),则不会触发后续元素。因此,你可以假设如果触发了后续元素,则订单已下达。

以下是来自 XMRBTC 的成功卖单输出示例:

Output of a successfully placed sell order

成功卖单

此行为使后续步骤更加舒适:你可以始终假设只要输出正确,订单就已下达。因此,你可以附加一个 基本操作 元素,该元素只需将输出写入 True 并将此值写入堆栈,以指示订单是否已下达。

如果出现问题,你可以在日志消息中找到详细信息(如果启用了日志记录)。

Logging output of Binance Order element

来自<0xC2><0xA0>Binance 订单元素的日志输出

计划和同步

对于定期调度和同步,请在网格 1 中的整个工作流程前面加上 Binance 调度器 元素。

Binance Scheduler at Grid 1, Position 1A

网格 1 中位置 1A 的 Binance 调度器

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

Grid 1: Split execution path

元素 5A 指向网格 2 的元素 1A,元素 5B 指向网格 1 的元素 1A(Binance 调度器)。

部署

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

PythonicDaemon console interface

PythonicDaemon 控制台

PythonicDaemon 是基本安装的一部分。要使用它,请保存你的完整工作流程,将其传输到远程运行系统(例如,通过安全复制 [SCP]),并使用工作流程文件作为参数启动 PythonicDaemon

$ PythonicDaemon trading_bot_one

要在系统启动时自动启动 PythonicDaemon,你可以向 crontab 添加一个条目

# crontab -e

Crontab on Ubuntu Server

下一步

正如我在开头写的那样,本教程只是自动化交易的起点。编程交易机器人大约是 10% 的编程和 90% 的测试。当涉及到让你的机器人用你的钱进行交易时,你肯定会对你编程的代码三思而后行。因此,我建议你尽可能保持代码简单易懂。

如果你想继续自己开发你的交易机器人,接下来要设置的是:

  • 自动利润计算(希望只有正数!)
  • 计算你想买入的价格
  • 与你的订单簿进行比较(即,订单是否已完全成交?)

你可以在 GitHub 上下载整个示例。

接下来阅读什么
标签
User profile image.
Stephan 是一位技术爱好者,他欣赏开源,因为它能深入了解事物的运作方式。Stephan 在工业自动化软件这个主要为专有领域的行业担任全职支持工程师。如果可能,他会从事他基于 Python 的开源项目、撰写文章或骑摩托车。

4 条评论

嗨,下载该工具的链接不起作用。你能给我一个有效的链接吗?

好文章。

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 获得许可。
© . All rights reserved.