Merge pull request #21374 from wyxplus/master

提交翻译
This commit is contained in:
Xingyu.Wang 2021-03-22 23:15:25 +08:00 committed by GitHub
commit 560be880f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 429 additions and 424 deletions

View File

@ -1,424 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: (wyxplus)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (How to automate your cryptocurrency trades with Python)
[#]: via: (https://opensource.com/article/20/4/python-crypto-trading-bot)
[#]: author: (Stephan Avenwedde https://opensource.com/users/hansic99)
How to automate your cryptocurrency trades with Python
======
In this tutorial, learn how to set up and use Pythonic, a graphical
programming tool that makes it easy for users to create Python
applications using ready-made function modules.
![scientific calculator][1]
Unlike traditional stock exchanges like the New York Stock Exchange that have fixed trading hours, cryptocurrencies are traded 24/7, which makes it impossible for anyone to monitor the market on their own.
Often in the past, I had to deal with the following questions related to my crypto trading:
* What happened overnight?
* Why are there no log entries?
* Why was this order placed?
* Why was no order placed?
The usual solution is to use a crypto trading bot that places orders for you when you are doing other things, like sleeping, being with your family, or enjoying your spare time. There are a lot of commercial solutions available, but I wanted an open source option, so I created the crypto-trading bot [Pythonic][2]. As [I wrote][3] in an introductory article last year, "Pythonic is a graphical programming tool that makes it easy for users to create Python applications using ready-made function modules." It originated as a cryptocurrency bot and has an extensive logging engine and well-tested, reusable parts such as schedulers and timers.
### Getting started
This hands-on tutorial teaches you how to get started with Pythonic for automated trading. It uses the example of trading [Tron][4] against [Bitcoin][5] on the [Binance][6] exchange platform. I choose these coins because of their volatility against each other, rather than any personal preference.
The bot will make decisions based on [exponential moving averages][7] (EMAs).
![TRX/BTC 1-hour candle chart][8]
TRX/BTC 1-hour candle chart
The EMA indicator is, in general, a weighted moving average that gives more weight to recent price data. Although a moving average may be a simple indicator, I've had good experiences using it.
The purple line in the chart above shows an EMA-25 indicator (meaning the last 25 values were taken into account).
The bot monitors the pitch between the current EMA-25 value (t0) and the previous EMA-25 value (t-1). If the pitch exceeds a certain value, it signals rising prices, and the bot will place a buy order. If the pitch falls below a certain value, the bot will place a sell order.
The pitch will be the main indicator for making decisions about trading. For this tutorial, it will be called the _trade factor_.
### Toolchain
The following tools are used in this tutorial:
* Binance expert trading view (visualizing data has been done by many others, so there's no need to reinvent the wheel by doing it yourself)
* Jupyter Notebook for data-science tasks
* Pythonic, which is the overall framework
* PythonicDaemon as the pure runtime (console- and Linux-only)
### Data mining
For a crypto trading bot to make good decisions, it's essential to get open-high-low-close ([OHLC][9]) data for your asset in a reliable way. You can use Pythonic's built-in elements and extend them with your own logic.
The general workflow is:
1. Synchronize with Binance time
2. Download OHLC data
3. Load existing OHLC data from the file into memory
4. Compare both datasets and extend the existing dataset with the newer rows
This workflow may be a bit overkill, but it makes this solution very robust against downtime and disconnections.
To begin, you need the **Binance OHLC Query** element and a **Basic Operation** element to execute your own code.
![Data-mining workflow][10]
Data-mining workflow
The OHLC query is set up to query the asset pair **TRXBTC** (Tron/Bitcoin) in one-hour intervals.
![Configuration of the OHLC query element][11]
Configuring the OHLC query element
The output of this element is a [Pandas DataFrame][12]. You can access the DataFrame with the **input** variable in the **Basic Operation** element. Here, the **Basic Operation** element is set up to use Vim as the default code editor.
![Basic Operation element set up to use Vim][13]
Basic Operation element set up to use Vim
Here is what the code looks like:
```
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
```
First, check whether the input is the DataFrame type. Then look inside the user's home directory (**~/**) for a file named **TRXBTC_1h.bin**. If it is present, then open it, concatenate new rows (the code in the **try** section), and drop overlapping duplicates. If the file doesn't exist, trigger an _exception_ and execute the code in the **except** section, creating a new file.
As long as the checkbox **log output** is enabled, you can follow the logging with the command-line tool **tail**:
```
`$ tail -f ~/Pythonic_2020/Feb/log_2020_02_19.txt`
```
For development purposes, skip the synchronization with Binance time and regular scheduling for now. This will be implemented below.
### Data preparation
The next step is to handle the evaluation logic in a separate grid; therefore, you have to pass over the DataFrame from Grid 1 to the first element of Grid 2 with the help of the **Return element**.
In Grid 2, extend the DataFrame by a column that contains the EMA values by passing the DataFrame through a **Basic Technical Analysis** element.
![Technical analysis workflow in Grid 2][14]
Technical analysis workflow in Grid 2
Configure the technical analysis element to calculate the EMAs over a period of 25 values.
![Configuration of the technical analysis element][15]
Configuring the technical analysis element
When you run the whole setup and activate the debug output of the **Technical Analysis** element, you will realize that the values of the EMA-25 column all seem to be the same.
![Missing decimal places in output][16]
Decimal places are missing in the output
This is because the EMA-25 values in the debug output include just six decimal places, even though the output retains the full precision of an 8-byte float value.
For further processing, add a **Basic Operation** element:
![Workflow in Grid 2][17]
Workflow in Grid 2
With the **Basic Operation** element, dump the DataFrame with the additional EMA-25 column so that it can be loaded into a Jupyter Notebook;
![Dump extended DataFrame to file][18]
Dump extended DataFrame to file
### Evaluation logic
Developing the evaluation logic inside Juypter Notebook enables you to access the code in a more direct way. To load the DataFrame, you need the following lines:
![Representation with all decimal places][19]
Representation with all decimal places
You can access the latest EMA-25 values by using [**iloc**][20] and the column name. This keeps all of the decimal places.
You already know how to get the latest value. The last line of the example above shows only the value. To copy the value to a separate variable, you have to access it with the **.at** method, as shown below.
You can also directly calculate the trade factor, which you will need in the next step.
![Buy/sell decision][21]
Buy/sell decision
### Determine the trading factor
As you can see in the code above, I chose 0.009 as the trade factor. But how do I know if 0.009 is a good trading factor for decisions? Actually, this factor is really bad, so instead, you can brute-force the best-performing trade factor.
Assume that you will buy or sell based on the closing price.
![Validation function][22]
Validation function
In this example, **buy_factor** and **sell_factor** are predefined. So extend the logic to brute-force the best performing values.
![Nested for loops for determining the buy and sell factor][23]
Nested _for_ loops for determining the buy and sell factor
This has 81 loops to process (9x9), which takes a couple of minutes on my machine (a Core i7 267QM).
![System utilization while brute forcing][24]
System utilization while brute-forcing
After each loop, it appends a tuple of **buy_factor**, **sell_factor**, and the resulting **profit** to the **trading_factors** list. Sort the list by profit in descending order.
![Sort profit with related trading factors in descending order][25]
Sort profit with related trading factors in descending order
When you print the list, you can see that 0.002 is the most promising factor.
![Sorted list of trading factors and profit][26]
Sorted list of trading factors and profit
When I wrote this in March 2020, the prices were not volatile enough to present more promising results. I got much better results in February, but even then, the best-performing trading factors were also around 0.002.
### Split the execution path
Start a new grid now to maintain clarity. Pass the DataFrame with the EMA-25 column from Grid 2 to element 0A of Grid 3 by using a **Return** element.
In Grid 3, add a **Basic Operation** element to execute the evaluation logic. Here is the code of that element:
![Implemented evaluation logic][27]
Implemented evaluation logic
The element outputs a **1** if you should buy or a **-1** if you should sell. An output of **0** means there's nothing to do right now. Use a **Branch** element to control the execution path.
![Branch element: Grid 3 Position 2A][28]
Branch element: Grid 3, Position 2A
Due to the fact that both **0** and **-1** are processed the same way, you need an additional Branch element on the right-most execution path to decide whether or not you should sell.
![Branch element: Grid 3 Position 3B][29]
Branch element: Grid 3, Position 3B
Grid 3 should now look like this:
![Workflow on Grid 3][30]
Workflow on Grid 3
### Execute orders
Since you cannot buy twice, you must keep a persistent variable between the cycles that indicates whether you have already bought.
You can do this with a **Stack element**. The Stack element is, as the name suggests, a representation of a file-based stack that can be filled with any Python data type.
You need to define that the stack contains only one Boolean element, which determines if you bought (**True**) or not (**False**). As a consequence, you have to preset the stack with one **False**. You can set this up, for example, in Grid 4 by simply passing a **False** to the stack.
![Forward a False-variable to the subsequent Stack element][31]
Forward a **False** variable to the subsequent Stack element
The Stack instances after the branch tree can be configured as follows:
![Configuration of the Stack element][32]
Configuring the Stack element
In the Stack element configuration, set **Do this with input** to **Nothing**. Otherwise, the Boolean value will be overwritten by a 1 or 0.
This configuration ensures that only one value is ever saved in the stack (**True** or **False**), and only one value can ever be read (for clarity).
Right after the Stack element, you need an additional **Branch** element to evaluate the stack value before you place the **Binance Order** elements.
![Evaluate the variable from the stack][33]
Evaluating the variable from the stack
Append the Binance Order element to the **True** path of the Branch element. The workflow on Grid 3 should now look like this:
![Workflow on Grid 3][34]
Workflow on Grid 3
The Binance Order element is configured as follows:
![Configuration of the Binance Order element][35]
Configuring the Binance Order element
You can generate the API and Secret keys on the Binance website under your account settings.
![Creating an API key in Binance][36]
Creating an API key in the Binance account settings
In this tutorial, every trade is executed as a market trade and has a volume of 10,000 TRX (~US$ 150 on March 2020). (For the purposes of this tutorial, I am demonstrating the overall process by using a Market Order. Because of that, I recommend using at least a Limit order.)
The subsequent element is not triggered if the order was not executed properly (e.g., a connection issue, insufficient funds, or incorrect currency pair). Therefore, you can assume that if the subsequent element is triggered, the order was placed.
Here is an example of output from a successful sell order for XMRBTC:
![Output of a successfully placed sell order][37]
Successful sell order output
This behavior makes subsequent steps more comfortable: You can always assume that as long the output is proper, the order was placed. Therefore, you can append a **Basic Operation** element that simply writes the output to **True** and writes this value on the stack to indicate whether the order was placed or not.
If something went wrong, you can find the details in the logging message (if logging is enabled).
![Logging output of Binance Order element][38]
Logging output from Binance Order element
### Schedule and sync
For regular scheduling and synchronization, prepend the entire workflow in Grid 1 with the **Binance Scheduler** element.
![Binance Scheduler at Grid 1, Position 1A][39]
Binance Scheduler at Grid 1, Position 1A
The Binance Scheduler element executes only once, so split the execution path on the end of Grid 1 and force it to re-synchronize itself by passing the output back to the Binance Scheduler element.
![Grid 1: Split execution path][40]
Grid 1: Split execution path
Element 5A points to Element 1A of Grid 2, and Element 5B points to Element 1A of Grid 1 (Binance Scheduler).
### Deploy
You can run the whole setup 24/7 on your local machine, or you could host it entirely on an inexpensive cloud system. For example, you can use a Linux/FreeBSD cloud system for about US$5 per month, but they usually don't provide a window system. If you want to take advantage of these low-cost clouds, you can use PythonicDaemon, which runs completely inside the terminal.
![PythonicDaemon console interface][41]
PythonicDaemon console
PythonicDaemon is part of the basic installation. To use it, save your complete workflow, transfer it to the remote running system (e.g., by Secure Copy [SCP]), and start PythonicDaemon with the workflow file as an argument:
```
`$ PythonicDaemon trading_bot_one`
```
To automatically start PythonicDaemon at system startup, you can add an entry to the crontab:
```
`# crontab -e`
```
![Crontab on Ubuntu Server][42]
Crontab on Ubuntu Server
### Next steps
As I wrote at the beginning, this tutorial is just a starting point into automated trading. Programming trading bots is approximately 10% programming and 90% testing. When it comes to letting your bot trade with your money, you will definitely think thrice about the code you program. So I advise you to keep your code as simple and easy to understand as you can.
If you want to continue developing your trading bot on your own, the next things to set up are:
* Automatic profit calculation (hopefully only positive!)
* Calculation of the prices you want to buy for
* Comparison with your order book (i.e., was the order filled completely?)
You can download the whole example on [GitHub][2].
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/4/python-crypto-trading-bot
作者:[Stephan Avenwedde][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/hansic99
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/calculator_money_currency_financial_tool.jpg?itok=2QMa1y8c (scientific calculator)
[2]: https://github.com/hANSIc99/Pythonic
[3]: https://opensource.com/article/19/5/graphically-programming-pythonic
[4]: https://tron.network/
[5]: https://bitcoin.org/en/
[6]: https://www.binance.com/
[7]: https://www.investopedia.com/terms/e/ema.asp
[8]: https://opensource.com/sites/default/files/uploads/1_ema-25.png (TRX/BTC 1-hour candle chart)
[9]: https://en.wikipedia.org/wiki/Open-high-low-close_chart
[10]: https://opensource.com/sites/default/files/uploads/2_data-mining-workflow.png (Data-mining workflow)
[11]: https://opensource.com/sites/default/files/uploads/3_ohlc-query.png (Configuration of the OHLC query element)
[12]: https://pandas.pydata.org/pandas-docs/stable/getting_started/dsintro.html#dataframe
[13]: https://opensource.com/sites/default/files/uploads/4_edit-basic-operation.png (Basic Operation element set up to use Vim)
[14]: https://opensource.com/sites/default/files/uploads/6_grid2-workflow.png (Technical analysis workflow in Grid 2)
[15]: https://opensource.com/sites/default/files/uploads/7_technical-analysis-config.png (Configuration of the technical analysis element)
[16]: https://opensource.com/sites/default/files/uploads/8_missing-decimals.png (Missing decimal places in output)
[17]: https://opensource.com/sites/default/files/uploads/9_basic-operation-element.png (Workflow in Grid 2)
[18]: https://opensource.com/sites/default/files/uploads/10_dump-extended-dataframe.png (Dump extended DataFrame to file)
[19]: https://opensource.com/sites/default/files/uploads/11_load-dataframe-decimals.png (Representation with all decimal places)
[20]: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.iloc.html
[21]: https://opensource.com/sites/default/files/uploads/12_trade-factor-decision.png (Buy/sell decision)
[22]: https://opensource.com/sites/default/files/uploads/13_validation-function.png (Validation function)
[23]: https://opensource.com/sites/default/files/uploads/14_brute-force-tf.png (Nested for loops for determining the buy and sell factor)
[24]: https://opensource.com/sites/default/files/uploads/15_system-utilization.png (System utilization while brute forcing)
[25]: https://opensource.com/sites/default/files/uploads/16_sort-profit.png (Sort profit with related trading factors in descending order)
[26]: https://opensource.com/sites/default/files/uploads/17_sorted-trading-factors.png (Sorted list of trading factors and profit)
[27]: https://opensource.com/sites/default/files/uploads/18_implemented-evaluation-logic.png (Implemented evaluation logic)
[28]: https://opensource.com/sites/default/files/uploads/19_output.png (Branch element: Grid 3 Position 2A)
[29]: https://opensource.com/sites/default/files/uploads/20_editbranch.png (Branch element: Grid 3 Position 3B)
[30]: https://opensource.com/sites/default/files/uploads/21_grid3-workflow.png (Workflow on Grid 3)
[31]: https://opensource.com/sites/default/files/uploads/22_pass-false-to-stack.png (Forward a False-variable to the subsequent Stack element)
[32]: https://opensource.com/sites/default/files/uploads/23_stack-config.png (Configuration of the Stack element)
[33]: https://opensource.com/sites/default/files/uploads/24_evaluate-stack-value.png (Evaluate the variable from the stack)
[34]: https://opensource.com/sites/default/files/uploads/25_grid3-workflow.png (Workflow on Grid 3)
[35]: https://opensource.com/sites/default/files/uploads/26_binance-order.png (Configuration of the Binance Order element)
[36]: https://opensource.com/sites/default/files/uploads/27_api-key-binance.png (Creating an API key in Binance)
[37]: https://opensource.com/sites/default/files/uploads/28_sell-order.png (Output of a successfully placed sell order)
[38]: https://opensource.com/sites/default/files/uploads/29_binance-order-output.png (Logging output of Binance Order element)
[39]: https://opensource.com/sites/default/files/uploads/30_binance-scheduler.png (Binance Scheduler at Grid 1, Position 1A)
[40]: https://opensource.com/sites/default/files/uploads/31_split-execution-path.png (Grid 1: Split execution path)
[41]: https://opensource.com/sites/default/files/uploads/32_pythonic-daemon.png (PythonicDaemon console interface)
[42]: https://opensource.com/sites/default/files/uploads/33_crontab.png (Crontab on Ubuntu Server)

View File

@ -0,0 +1,429 @@
[#]: collector: (lujun9972)
[#]: translator: (wyxplus)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (How to automate your cryptocurrency trades with Python)
[#]: via: (https://opensource.com/article/20/4/python-crypto-trading-bot)
[#]: author: (Stephan Avenwedde https://opensource.com/users/hansic99)
如何使用 Python 来自动交易加密货币
======
在本教程中,教你如何设置和使用 Pythonic 来编程。它是一个图形化编程工具,用户可以很容易地使用现成的函数模块创建 Python 程序。
![scientific calculator][1]
然而,不像纽约证券交易所这样的传统证券交易所一样,有一段固定的交易时间。对于加密货币而言,则是 7×24 小时交易,任何人都无法独自盯着市场。
在以前,我经常思考与加密货币交易相关的问题:
- 一夜之间发生了什么?
- 为什么没有日志记录?
- 为什么下单?
- 为什么不下单?
通常的解决手段是当在你做其他事情时,例如睡觉、与家人在一起或享受空闲时光,使用加密交易机器人代替你下单。虽然有很多商业解决方案可用,但是我选择开源的解决方案,因此我编写了加密交易机器人 [Pythonic][2]。 正如去年 [我写过的文章][3] 一样,“ Pythonic 是一种图形化编程工具它让用户可以轻松使用现成的功能模块来创建Python应用程序。” 最初它是作为加密货币机器人使用,并具有可扩展的日志记录引擎以及经过精心测试的可重用部件,例如调度器和计时器。
### 开始
本教程将教你如何开始使用 Pythonic 进行自动交易。我选择 [币安][6]Binance<ruby>[币安][6]<rt>Binance</rt></ruby> 交易所的 [波场][4]Tron<ruby>[波场][4]<rt>Tron</rt></ruby> 与 [比特币][3]Bitcoin<ruby>[比特币][3]<rt>Bitcoin</rt></ruby>
交易对为例。我之所以选择这些加密货币,是因为它们彼此之间的波动性大,而不是出于个人喜好。
机器人将根据 [指数移动平均][7] EMAs来做出决策。
![TRX/BTC 1-hour candle chart][8]
TRX/BTC 1 小时 K 线图
EMA 指标通常是指加权移动平均线,可以对近期价格数据赋予更多权重。尽管移动平均线可能只是一个简单的指标,但我能熟练使用它。
上图中的紫色线显示了 EMA-25 指标(这表示要考虑最近的 25 个值)。
机器人监视当前的 EMA-25 值t0和前一个 EMA-25 值t-1之间的差距。如果差值超过某个值则表示价格上涨机器人将下达购买订单。如果差值低于某个值则机器人将下达卖单。
差值将是做出交易决策的主要指标。在本教程中,它称为交易参数。
### 工具链
将在本教程使用如下工具:
- 币安专业交易视图(已经有其他人做了数据可视化,所以不需要重复造轮子)
- Jupyter Notebook用于数据科学任务
- Pythonic作为整体框架
- PythonicDaemon :作为终端运行(仅适用于控制台和 Linux
### 数据挖掘
为了使加密货币交易机器人尽可能能做出正确的决定,以可靠的方式获取资产的美国线([OHLC][9])数据是至关重要。你可以使用 Pythonic 的内置元素,还可以根据自己逻辑来对其进行扩展。
一般的工作流程:
1. 与币安时间同步
2. 下载 OHLC 数据
3. 从文件中把 OHLC 数据加载到内存
4. 比较数据集并扩展更新数据集
这个工作流程可能有点夸张,但是它能使得程序更加健壮,甚至在停机和断开连接时,也能平稳运行。
一开始,你需要 **币安 OHLC 查询**Binance OHLC Query<ruby>**币安 OHLC 查询**<rt>Binance OHLC Query</rt></ruby> 元素和一个 **基础操作**Basic Operation<ruby>**基础操作**<rt>Basic Operation</rt></ruby> 元素来执行你的代码。
![Data-mining workflow][10]
数据挖掘工作流程
OHLC 查询设置为每隔一小时查询一次 **TRXBTC** 资产对(波场/比特币)。
![Configuration of the OHLC query element][11]
配置 OHLC 查询元素
其中输出的元素是 [Pandas DataFrame][12]。你可以在 **基础操作** 元素中使用 **输入**input<ruby>**输入**<rt>input</rt></ruby> 变量来访问 DataFrame。其中将 Vim 设置为 **基础操作** 元素的默认代码编辑器。
![Basic Operation element set up to use Vim][13]
使用 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<ruby>**日志输出**<rt>log output</rt></ruby>,你就可以使用命令行工具 **tail** 查看日志记录:
```
`$ tail -f ~/Pythonic_2020/Feb/log_2020_02_19.txt`
```
出于开发目的,现在跳过与币安时间的同步和计划执行,这将在下面实现。
### 准备数据
下一步是在单独的 网格Grid<ruby>网格<rt>Grid</rt></ruby> 中处理评估逻辑。因此,你必须借助 **返回元素**Return element<ruby>**返回元素**<rt>Return element</rt></ruby> 将 DataFrame 从网格 1 传递到网格 2 的第一个元素。
在网格 2 中,通过使 DataFrame 通过 **基础技术分析**Basic Technical Analysis<ruby>**基础技术分析**<rt>Basic Technical Analysis</rt></ruby> 元素,将 DataFrame 扩展包含 EMA 值的一列。
![Technical analysis workflow in Grid 2][14]
在网格 2 中技术分析工作流程
配置技术分析元素以计算 25 个值的 EMAs。
![Configuration of the technical analysis element][15]
配置技术分析元素
当你运行整个程序并开启 **技术分析**Technical Analysis<ruby>**技术分析**<rt>Technical Analysis</rt></ruby> 元素的调试输出时,你将发现 EMA-25 列的值似乎都相同。
![Missing decimal places in output][16]
输出中精度不够
这是因为调试输出中的 EMA-25 值仅包含六位小数,即使输出保留了 8 个字节完整精度的浮点值。
为了能进行进一步处理,请添加 **基础操作** 元素:
![Workflow in Grid 2][17]
网格 2 中的工作流程
使用 **基础操作** 元素,将 DataFrame 与添加的 EMA-25 列一起转储,以便可以将其加载到 Jupyter Notebook中
![Dump extended DataFrame to file][18]
将扩展后的 DataFrame 存储到文件中
### 评估策略
在 Juypter Notebook 中开发评估策略,让你可以更直接地访问代码。要加载 DataFrame你需要使用如下代码
![Representation with all decimal places][19]
用全部小数位表示
你可以使用 [**iloc**][20] 和列名来访问最新的 EMA-25 值,并且会保留所有小数位。
你已经知道如何来获得最新的数据。上面示例的最后一行仅显示该值。为了能将该值拷贝到不同的变量中,你必须使用如下图所示的 **.at** 方法方能成功。
你也可以直接计算出你下一步所需的交易参数。
![Buy/sell decision][21]
买卖决策
### 确定交易参数
如上面代码所示,我选择 0.009 作为交易参数。但是我怎么知道 0.009 是决定交易的一个好参数呢? 实际上,这个参数确实很糟糕,因此,你可以直接计算出表现最佳的交易参数。
假设你将根据收盘价进行买卖。
![Validation function][22]
回测功能
在此示例中,**buy_factor** 和 **sell_factor** 是预先定义好的。因此,发散思维用直接计算出表现最佳的参数。
![Nested for loops for determining the buy and sell factor][23]
嵌套的 _for_ 循环,用于确定购买和出售的参数
这要跑 81 个循环9x9在我的机器Core i7 267QM上花费了几分钟。
![System utilization while brute forcing][24]
在暴力运算时系统的利用率
在每个循环之后,它将 **buy_factor****sell_factor** 元组和生成的 **利润**profit<ruby>**利润**<rt>profit</rt></ruby> 元组追加到 **trading_factors** 列表中。按利润降序对列表进行排序。
![Sort profit with related trading factors in descending order][25]
将利润与相关的交易参数按降序排序
当你打印出列表时,你会看到 0.002 是最好的参数。
![Sorted list of trading factors and profit][26]
交易要素和收益的有序列表
当我在 2020 年 3 月写下这篇文章时,价格的波动还不足以呈现出更理想的结果。我在 2 月份得到了更好的结果,但即使在那个时候,表现最好的交易参数也在 0.002 左右。
### 分割执行路径
现在开始新建一个网格以保持逻辑清晰。使用 **返回** 元素将带有 EMA-25 列的 DataFrame 从网格 2 传递到网格 3 的 0A 元素。
在网格 3 中,添加 **基础操作** 元素以执行评估逻辑。这是该元素中的代码:
![Implemented evaluation logic][27]
实现评估策略
如果输出 **1** 表示你应该购买,如果输出 **2** 则表示你应该卖出。 输出 **0** 表示现在无需操作。使用 **分支**Branch<ruby>**分支**<rt>Branch</rt></ruby> 元素来控制执行路径。
![Branch element: Grid 3 Position 2A][28]
Branch 元素:网格 32A 位置
因为 **0****-1** 的处理流程一样,所以你需要在最右边添加一个分支元素来判断你是否应该卖出。
![Branch element: Grid 3 Position 3B][29]
分支元素:网格 33B 位置
网格 3 应该现在如下图所示:
![Workflow on Grid 3][30]
网格 3 的工作流程
### 下单
由于无需在一个周期中购买两次,因此必须在周期之间保留一个持久变量,以指示你是否已经购买。
你可以利用 **栈**Stack<ruby>**栈**<rt>Stack</rt></ruby> 元素来实现。顾名思义,栈元素表示可以用任何 Python 数据类型来放入的基于文件的栈。
你需要定义栈仅包含一个布尔类型,该布尔类型决定是否购买了(**True**)或(**False**)。因此,你必须使用 **False** 来初始化栈。例如,你可以在网格 4 中简单地通过将 **False** 传递给栈来进行设置。![Forward a False-variable to the subsequent Stack element][31]
**False** 变量传输到后续的栈元素中
在分支树后的栈实例可以进行如下配置:
![Configuration of the Stack element][32]
设置栈元素
在栈元素设置中,将 **Do this with input** 设置成 **Nothing**。否则,布尔值将被 1 或 0 覆盖。
该设置确保仅将一个值保存于栈中(**True** 或 **False**),并且只能读取一个值(为了清楚起见)。
在栈元素之后,你需要另外一个 **分支** 元素来判断栈的值,然后再放置 **币安订单**Binance Order<ruby>**币安订单**<rt>Binance Order</rt></ruby> 元素。
![Evaluate the variable from the stack][33]
判断栈中的变量
将币安订单元素添加到分支元素的 **True** 路径。网格 3 上的工作流现在应如下所示:
![Workflow on Grid 3][34]
网格 3 的工作流程
币安订单元素应如下配置:
![Configuration of the Binance Order element][35]
编辑币安订单元素
你可以在币安网站上的帐户设置中生成 API 和密钥。
![Creating an API key in Binance][36]
在币安账户设置中创建一个 API key
在本文中每笔交易都是作为市价交易执行的交易量为10,000 TRX2020 年 3 月约为 150 美元)(出于教学的目的,我通过使用市价下单来演示整个过程。因此,我建议至少使用限价下单。)
如果未正确执行下单(例如,网络问题、资金不足或货币对不正确),则不会触发后续元素。因此,你可以假定如果触发了后续元素,则表示该订单已下达。
这是一个成功的 XMRBTC 卖单的输出示例:
![Output of a successfully placed sell order][37]
成功卖单的输出
该行为使后续步骤更加简单:你可以始终假设只要成功输出,就表示订单成功。因此,你可以添加一个 **基础操作** 元素,该元素将简单地输出 **True** 并将此值放入栈中以表示是否下单。
如果出现错误的话,你可以在日志信息中查看具体细节(如果启用日志功能)。
![Logging output of Binance Order element][38]
币安订单元素中的输出日志信息
### 调度和同步
对于日程调度和同步,请在网格 1 中将整个工作流程置于 **币安调度器**Binance Scheduler<ruby>**币安调度器**<rt>Binance Scheduler</rt></ruby> 元素的前面。
![Binance Scheduler at Grid 1, Position 1A][39]
在网格 11A 位置的币安调度器
由于币安调度器元素只执行一次,因此请在网格 1 的末尾拆分执行路径,并通过将输出传递回币安调度器来强制让其重新同步。
![Grid 1: Split execution path][40]
网格 1拆分执行路径
5A 元素指向 网格 2 的 1A 元素,并且 5B 元素指向网格 1 的 1A 元素(币安调度器)。
### 部署
你可以在本地计算机上全天候 7×24 小时运行整个程序,也可以将其完全托管在廉价的云系统上。例如,你可以使用 Linux/FreeBSD 云系统,每月约 5 美元,但通常不提供图形化界面。如果你想利用这些低成本的云,可以使用 PythonicDaemon它能在终端中完全运行。
![PythonicDaemon console interface][41]
PythonicDaemon 控制台
PythonicDaemon 是基础程序的一部分。要使用它请保存完整的工作流程将其传输到远程运行的系统中例如通过安全拷贝协议Secure Copy<ruby>安全拷贝协议<rt>Secure Copy</rt></ruby> [SCP]),然后把工作流程文件作为参数来启动 PythonicDaemon
```
`$ PythonicDaemon trading_bot_one`
```
为了能在系统启动时自启 PythonicDaemon可以将一个条目添加到 crontab 中:
```
`# crontab -e`
```
![Crontab on Ubuntu Server][42]
在 Ubuntu 服务器上的 Crontab
### 下一步
正如我在一开始时所说的,本教程只是自动交易的入门。对交易机器人进行编程大约需要 10 的编程和 90 的测试。当涉及到让你的机器人用金钱交易时,你肯定会对编写的代码再三思考。因此,我建议你编码时要尽可能简单和易于理解。
如果你想自己继续开发交易机器人,接下来所需要做的事:
- 收益自动计算(希望你有正收益!)
- 计算你想买的价格
- 比较你的预订单(例如,订单是否填写完整?)
你可以从 [GitHub][2] 上获取完整代码。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/4/python-crypto-trading-bot
作者:[Stephan Avenwedde][a]
选题:[lujun9972][b]
译者:[wyxplus](https://github.com/wyxplus)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/hansic99
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/calculator_money_currency_financial_tool.jpg?itok=2QMa1y8c "scientific calculator"
[2]: https://github.com/hANSIc99/Pythonic
[3]: https://opensource.com/article/19/5/graphically-programming-pythonic
[4]: https://tron.network/
[5]: https://bitcoin.org/en/
[6]: https://www.binance.com/
[7]: https://www.investopedia.com/terms/e/ema.asp
[8]: https://opensource.com/sites/default/files/uploads/1_ema-25.png "TRX/BTC 1-hour candle chart"
[9]: https://en.wikipedia.org/wiki/Open-high-low-close_chart
[10]: https://opensource.com/sites/default/files/uploads/2_data-mining-workflow.png "Data-mining workflow"
[11]: https://opensource.com/sites/default/files/uploads/3_ohlc-query.png "Configuration of the OHLC query element"
[12]: https://pandas.pydata.org/pandas-docs/stable/getting_started/dsintro.html#dataframe
[13]: https://opensource.com/sites/default/files/uploads/4_edit-basic-operation.png "Basic Operation element set up to use Vim"
[14]: https://opensource.com/sites/default/files/uploads/6_grid2-workflow.png "Technical analysis workflow in Grid 2"
[15]: https://opensource.com/sites/default/files/uploads/7_technical-analysis-config.png "Configuration of the technical analysis element"
[16]: https://opensource.com/sites/default/files/uploads/8_missing-decimals.png "Missing decimal places in output"
[17]: https://opensource.com/sites/default/files/uploads/9_basic-operation-element.png "Workflow in Grid 2"
[18]: https://opensource.com/sites/default/files/uploads/10_dump-extended-dataframe.png "Dump extended DataFrame to file"
[19]: https://opensource.com/sites/default/files/uploads/11_load-dataframe-decimals.png "Representation with all decimal places"
[20]: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.iloc.html
[21]: https://opensource.com/sites/default/files/uploads/12_trade-factor-decision.png "Buy/sell decision"
[22]: https://opensource.com/sites/default/files/uploads/13_validation-function.png "Validation function"
[23]: https://opensource.com/sites/default/files/uploads/14_brute-force-tf.png "Nested for loops for determining the buy and sell factor"
[24]: https://opensource.com/sites/default/files/uploads/15_system-utilization.png "System utilization while brute forcing"
[25]: https://opensource.com/sites/default/files/uploads/16_sort-profit.png "Sort profit with related trading factors in descending order"
[26]: https://opensource.com/sites/default/files/uploads/17_sorted-trading-factors.png "Sorted list of trading factors and profit"
[27]: https://opensource.com/sites/default/files/uploads/18_implemented-evaluation-logic.png "Implemented evaluation logic"
[28]: https://opensource.com/sites/default/files/uploads/19_output.png "Branch element: Grid 3 Position 2A"
[29]: https://opensource.com/sites/default/files/uploads/20_editbranch.png "Branch element: Grid 3 Position 3B"
[30]: https://opensource.com/sites/default/files/uploads/21_grid3-workflow.png "Workflow on Grid 3"
[31]: https://opensource.com/sites/default/files/uploads/22_pass-false-to-stack.png "Forward a False-variable to the subsequent Stack element"
[32]: https://opensource.com/sites/default/files/uploads/23_stack-config.png "Configuration of the Stack element"
[33]: https://opensource.com/sites/default/files/uploads/24_evaluate-stack-value.png "Evaluate the variable from the stack"
[34]: https://opensource.com/sites/default/files/uploads/25_grid3-workflow.png "Workflow on Grid 3"
[35]: https://opensource.com/sites/default/files/uploads/26_binance-order.png "Configuration of the Binance Order element"
[36]: https://opensource.com/sites/default/files/uploads/27_api-key-binance.png "Creating an API key in Binance"
[37]: https://opensource.com/sites/default/files/uploads/28_sell-order.png "Output of a successfully placed sell order"
[38]: https://opensource.com/sites/default/files/uploads/29_binance-order-output.png "Logging output of Binance Order element"
[39]: https://opensource.com/sites/default/files/uploads/30_binance-scheduler.png "Binance Scheduler at Grid 1, Position 1A"
[40]: https://opensource.com/sites/default/files/uploads/31_split-execution-path.png "Grid 1: Split execution path"
[41]: https://opensource.com/sites/default/files/uploads/32_pythonic-daemon.png "PythonicDaemon console interface"
[42]: https://opensource.com/sites/default/files/uploads/33_crontab.png "Crontab on Ubuntu Server"