如何使用 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 用于<0xC2><0xA0>数据科学任务
  • Pythonic,它是<0xC2><0xA0>总体框架
  • PythonicDaemon 作为<0xC2><0xA0>纯运行时(仅限控制台和 Linux)

数据挖掘

为了让加密货币交易机器人做出好的决策,以可靠的方式获取资产的开盘价-最高价-最低价-收盘价 (OHLC) 数据至关重要。您可以使用 Pythonic 的内置元素并使用自己的逻辑扩展它们。

一般工作流程是:

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

此工作流程可能有点过分,但它使此解决方案非常强大,可以抵抗停机和断开连接。

要开始,您需要 Binance OHLC Query 元素和一个 Basic Operation 元素来执行您自己的代码。

Data-mining workflow

数据挖掘工作流程

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

Configuration of the OHLC query element

配置 OHLC 查询元素

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

Basic Operation element set up to use Vim

Basic Operation 元素设置为使用 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 部分中的代码),并删除重叠的重复项。如果该文件不存在,则触发一个 exception 并执行 except 部分中的代码,创建一个新文件。

只要启用复选框 log output,您就可以使用命令行工具 tail 跟踪日志记录。

$ tail -f ~/Pythonic_2020/Feb/log_2020_02_19.txt

出于开发目的,现在跳过与 Binance 时间的同步和定期调度。这将在下面实现。

数据准备

下一步是在单独的网格中处理评估逻辑;因此,您必须借助 Return element 将 DataFrame 从网格 1 传递到网格 2 的第一个元素。

在网格 2 中,通过 Basic Technical Analysis 元素传递 DataFrame,从而通过包含 EMA 值的列来扩展 DataFrame。

Technical analysis workflow in Grid 2

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

Configuration of the technical analysis element

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

当您运行整个设置并激活 Technical Analysis 元素的调试输出时,您将意识到 EMA-25 列的值看起来都相同。

Missing decimal places in output

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

为了进一步处理,添加一个 Basic Operation 元素

Workflow in Grid 2

网格 2 中的工作流程

使用 Basic Operation 元素,转储带有附加 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。

拆分执行路径

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

在网格 3 中,添加一个 Basic Operation 元素来执行评估逻辑。以下是该元素的代码:

Implemented evaluation logic

如果应该买入,则元素输出 1;如果应该卖出,则输出 -1。输出 0 表示现在没事可做。使用 Branch 元素来控制执行路径。

Branch element: Grid 3 Position 2A

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

Branch element: Grid 3 Position 3B

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

Workflow on Grid 3

执行订单

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

您可以使用 Stack element 来执行此操作。顾名思义,Stack 元素是基于文件的堆栈的表示,可以填充任何 Python 数据类型。

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

Forward a False-variable to the subsequent Stack element

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

Configuration of the Stack element

配置 Stack 元素

在 Stack 元素配置中,将 Do this with input 设置为 Nothing。否则,布尔值将被 1 或 0 覆盖。

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

在 Stack 元素之后,您需要一个额外的 Branch 元素来评估堆栈值,然后再放置 Binance Order 元素。

Evaluate the variable from the stack

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

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

Workflow on Grid 3

Binance Order 元素配置如下:

Configuration of the Binance Order element

配置<0xC2><0xA0>Binance Order 元素

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

Creating an API key in Binance

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

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

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

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

Output of a successfully placed sell order

成功的卖出订单

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

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

Logging output of Binance Order element

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

计划和同步

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

Binance Scheduler at Grid 1, Position 1A

网格 1 中位置 1A 的 Binance Scheduler

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

Grid 1: Split execution path

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

部署

您可以在本地机器上 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.