所有由Python实用宝典发布的文章

Asciinema – 终端日志记录神器,机器学习开发者的福音

我们在做机器学习/深度学习开发的时候,经常会产生如下所示的大量日志:

这些日志如果不保存,转瞬即逝,当我们想要回去翻看某一轮训练日志的时候,会很遗憾的发现找不到了。

现在有了这个 Asciinema 这个神器,我们不仅能找到当时的终端日志导出,还能够“重播日志”并“分享日志”。非常牛逼:

Asciinema 是使用Python开发的工具,请按下面的流程安装并使用。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install asciinema

2.Asciinema 使用方法

终端输入如下命令,记录你的第一个终端日志:

asciinema rec first.cast

输入完成后会显示如下的提示:

(gs3_9) zjr@sgd-linux-1:~/cnn_test$ asciinema rec first.cast
  
asciinema: recording asciicast to first.cast
asciinema: press <ctrl-d> or type "exit" when you're done

意思就是日志会被保存在当前文件夹下的first.cast,如果你想结束录制,按 Ctrl + D 即可。

记录完毕后,以双倍速度重播该日志:

asciinema play -s 2 first.cast

或以正常速度但空闲时间限制为 2 秒:

asciinema play -i 2 first.cast

你也可以在启动终端日志录制时传递 -i 2 asciinema rec,将其永久设置在录制中:

asciinema rec first.cast -i 2

空闲时间的限制使录制更有趣。试试吧。

如果你想在网络上观看和分享,请上传:

asciinema upload first.cast

这个命令会将日志记录上传到 asciinema.org,此外,它会打印一个秘密链接,你可以使用该链接在网络浏览器中观看你录制的终端日志:

你可以通过省略文件名一步录制和上传终端的日志:

asciinema rec

录制完成后,系统会要求你确认上传。未经你的同意,不会向任何地方发送任何内容。

3.播放日志

查看日志有四种方式,最普通的是通过本地文件进行终端重播:

asciinema play /path/to/asciicast.cast

以下键盘快捷键可用:

  • Space– 暂停,
  • .– 按帧步进(暂停时),
  • Ctrl+C– 退出

第二种方式是通过url播放:

asciinema play https://asciinema.org/a/22124.cast
asciinema play http://example.com/demo.cast

这个方式需要你的日志已经上传到asciinema.org中。

第三种方式是通过你自己生成的html页面访问(需要<link rel="alternate" type="application/x-asciicast" href="/my/ascii.cast">在页面的 HTML 中):

asciinema play http://your_html_path/post.html

第四种方式是通过标准输入输出播放:

cat /path/to/asciicast.cast | asciinema play -
ssh user@host cat asciicast.cast | asciinema play -

可用选项:

  • -i, --idle-time-limit=<sec>– 将重播的终端空闲不动时间闲置为最大<sec>秒数
  • -s, --speed=<factor>– 播放速度

4.导出日志

导出终端日志到文本文件非常简单:

asciinema cat existing.cast > terminal_output.txt

所有的终端日志都会被导出到 terminal_output.txt 中,非常方便好用。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

NNI 一个Python帮你自动做机器学习调参的神器

NNI 自动机器学习调参,是微软开源的又一个神器,它能帮助你找到最好的神经网络架构或超参数,支持各种训练环境

它常用的使用场景如下:

  • 想要在自己的代码、模型中试验不同的机器学习算法
  • 想要在不同的环境中加速运行机器学习。
  • 想要更容易实现或试验新的机器学习算法的研究员或数据科学家,包括:超参调优算法,神经网络搜索算法以及模型压缩算法。

它支持的框架有:

  • PyTorch
  • Keras
  • TensorFlow
  • MXNet
  • Caffe2
  • Scikit-learn
  • XGBoost
  • LightGBM

基本上市面上所有的深度学习和机器学习的框架它都支持。

下面就来看看怎么使用这个工具。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install --upgrade nni

2.NNI 机器学习调参运行示例

让我们运行一个示例来验证是否安装成功,首先克隆项目:

git clone -b v2.6 https://github.com/Microsoft/nni.git

(如果你无法成功克隆项目,请在Python实用宝典后台回复nni下载项目)

运行 MNIST-PYTORCH 示例,Linux/macOS:

nnictl create --config nni/examples/trials/mnist-pytorch/config.yml

Windows:

nnictl create --config nni\examples\trials\mnist-pytorch\config_windows.yml

出现这样的界面就说明安装成功,示例运行正常:

访问 http://127.0.0.1:8080 可以配置运行时间、实验次数等:

3.模型自动调参配置

那么如何让它和我们自己的模型适配呢?

观察 config_windows.yaml 会发现:

searchSpaceFile: search_space.json
trialCommand: python mnist.py
trialGpuNumber: 0
trialConcurrency: 1
tuner:
  name: TPE
  classArgs:
    optimize_mode: maximize
trainingService:
  platform: local

我们先看看 trialCommand, 这很明显是训练使用的命令,训练代码位于 mnist.py,其中有部分代码如下:

def get_params():
    # Training settings
    parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
    parser.add_argument("--data_dir", type=str,
                        default='./data', help="data directory")
    parser.add_argument('--batch_size', type=int, default=64, metavar='N',
                        help='input batch size for training (default: 64)')
    parser.add_argument("--batch_num", type=int, default=None)
    parser.add_argument("--hidden_size", type=int, default=512, metavar='N',
                        help='hidden layer size (default: 512)')
    parser.add_argument('--lr', type=float, default=0.01, metavar='LR',
                        help='learning rate (default: 0.01)')
    parser.add_argument('--momentum', type=float, default=0.5, metavar='M',
                        help='SGD momentum (default: 0.5)')
    parser.add_argument('--epochs', type=int, default=10, metavar='N',
                        help='number of epochs to train (default: 10)')
    parser.add_argument('--seed', type=int, default=1, metavar='S',
                        help='random seed (default: 1)')
    parser.add_argument('--no_cuda', action='store_true', default=False,
                        help='disables CUDA training')
    parser.add_argument('--log_interval', type=int, default=1000, metavar='N',
                        help='how many batches to wait before logging training status')


    args, _ = parser.parse_known_args()
    return args

如上所示,这个模型里提供了 10 个参数选择。也就是说 NNI 可以帮我们自动测试这10个参数。

那么这些参数在哪里设定?答案是在 searchSpaceFile 中,对应的值也就是 search_space.json:

{
    "batch_size": {"_type":"choice", "_value": [16, 32, 64, 128]},
    "hidden_size":{"_type":"choice","_value":[128, 256, 512, 1024]},
    "lr":{"_type":"choice","_value":[0.0001, 0.001, 0.01, 0.1]},
    "momentum":{"_type":"uniform","_value":[0, 1]}
}

这里有4个选项,NNI 是怎么组合这些参数的呢?这就是tuner参数干的事,为了让机器学习和深度学习模型适应不同的任务和问题,我们需要进行超参数调优,而自动化调优依赖于优秀的调优算法。NNI 内置了先进的调优算法,并且提供了易于使用的 API。

在 NNI 中,调优算法被称为“tuner”。Tuner 向 trial 发送超参数,接收运行结果从而评估这组超参的性能,然后将下一组超参发送给新的 trial。

下表简要介绍了 NNI 内置的调优算法。

Tuner算法简介
TPETree-structured Parzen Estimator (TPE) 是一种基于序列模型的优化方法 (sequential model-based optimization, SMBO)。SMBO方法根据历史数据来顺序地构造模型,从而预估超参性能,并基于此模型来选择新的超参。参考论文
Random Search (随机搜索)随机搜索在超算优化中表现出了令人意外的性能。如果没有对超参分布的先验知识,我们推荐使用随机搜索作为基线方法。参考论文
Anneal (退火)朴素退火算法首先基于先验进行采样,然后逐渐逼近实际性能较好的采样点。该算法是随即搜索的变体,利用了反应曲面的平滑性。该实现中退火率不是自适应的。
Naive Evolution(朴素进化)朴素进化算法来自于 Large-Scale Evolution of Image Classifiers。它基于搜索空间随机生成一个种群,在每一代中选择较好的结果,并对其下一代进行变异。朴素进化算法需要很多 Trial 才能取得最优效果,但它也非常简单,易于扩展。参考论文
SMACSMAC 是基于序列模型的优化方法 (SMBO)。它利用使用过的最突出的模型(高斯随机过程模型),并将随机森林引入到SMBO中,来处理分类参数。NNI 的 SMAC tuner 封装了 GitHub 上的 SMAC3参考论文注意:SMAC 算法需要使用 pip install nni[SMAC] 安装依赖,暂不支持 Windows 操作系统。
Batch(批处理)批处理允许用户直接提供若干组配置,为每种配置运行一个 trial。
Grid Search(网格遍历)网格遍历会穷举搜索空间中的所有超参组合。
HyperbandHyperband 试图用有限的资源探索尽可能多的超参组合。该算法的思路是,首先生成大量超参配置,将每组超参运行较短的一段时间,随后抛弃其中效果较差的一半,让较好的超参继续运行,如此重复多轮。参考论文
Metis大多数调参工具仅仅预测最优配置,而 Metis 的优势在于它有两个输出:(a) 最优配置的当前预测结果, 以及 (b) 下一次 trial 的建议。大多数工具假设训练集没有噪声数据,但 Metis 会知道是否需要对某个超参重新采样。参考论文
BOHBBOHB 是 Hyperband 算法的后续工作。 Hyperband 在生成新的配置时,没有利用已有的 trial 结果,而本算法利用了 trial 结果。BOHB 中,HB 表示 Hyperband,BO 表示贝叶斯优化(Byesian Optimization)。 BOHB 会建立多个 TPE 模型,从而利用已完成的 Trial 生成新的配置。参考论文
GP (高斯过程)GP Tuner 是基于序列模型的优化方法 (SMBO),使用高斯过程进行 surrogate。参考论文
PBTPBT Tuner 是一种简单的异步优化算法,在固定的计算资源下,它能有效的联合优化一组模型及其超参来最优化性能。参考论文
DNGODNGO 是基于序列模型的优化方法 (SMBO),该算法使用神经网络(而不是高斯过程)去建模贝叶斯优化中所需要的函数分布。

可以看到示例中,选择的是TPE tuner.

其他的参数比如 trialGpuNumber,指的是使用的gpu数量,trialConcurrency 指的是并发数。trainingService 中 platform 为 local,指的是本地训练。

当然,还有许多参数可以选,比如:

trialConcurrency: 2                 # 同时运行 2 个 trial
maxTrialNumber: 10                  # 最多生成 10 个 trial
maxExperimentDuration: 1h           # 1 小时后停止生成 trial

不过这些参数在调优开始时的web页面上是可以进行调整的。

所以其实NNI干的事情就很清楚了,也很简单。你只需要在你的模型训练文件中增加你想要调优的参数作为输入,就能使用NNI内置的调优算法对不同的参数进行调优,而且允许从页面UI上观察调优的整个过程,相对而言还是很方便的。

不过,NNI可能不太适用一些数据量极大或模型比较复杂的情况。比如基于DDP开发的模型,在NNI中可能无法实现大型的分布式计算。

当然,绝大多数情况下的训练任务,NNI都可以用得上。大家有兴趣深入使用的可以阅读NNI官方文档:https://nni.readthedocs.io/

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

超级安全!Python Pillow合成多张图片到PDF格式

在日常生活中,经常会遇到需要提交身份证正反面证明资料的情况,而且这些网站大部分只接受pdf格式,这时候我们就需要把身份证正反面两张图片合成为一个pdf文件。

在macOS系统下,预览软件可以轻松做到这一点,同时打开图片到一个预览窗口下,点击导出PDF就能成功导出。但是Windows系统就没有这么方便的软件可以实现这一点,网上有很多合成PDF的网站,但是这些网站无一例外需要上传PDF进行合成,个人认为非常地不安全。

因此,最安全的方法,还是我们自己写一个Python脚本实现合成功能。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install pillow

2.Pillow 合成PDF原理

Pillow模块,即PIL:Python Imaging Library,已经是Python平台事实上的图像处理标准库了。PIL功能非常强大,但API却非常简单易用。通过它,我们能很轻松地操作图像,并导出为不同格式。

首先来一个简单的示例,我们将打开一张图片,并将其保存为pdf格式:

from PIL import Image
import os


def convert_img_pdf(filepath, output_path):
    """
    转换图片为pdf格式

    Args:
        filepath (str): 文件路径
        output_path (str): 输出路径
    """
    output = Image.open(filepath)
    output.save(output_path, "pdf", save_all=True)
    
    
if __name__ == "__main__":
    convert_img_pdf("1.jpeg", "./test.pdf")

随便使用一张图片测试一下:

在运行代码后,它便成功地转化为了PDF文件:

几行代码便完成了这个转换,这个可比那些把照片上传到云端的网站安全多了。

3.多张照片合成PDF

有了前面照片转化PDF的基础知识,想要理解下面的多图合成PDF的代码就非常简单了。

其实就是使用了.save的一个特殊参数 append_images:

output.save(pdfFilePath, "pdf", save_all=True, append_images=sources)

通过把图片都存入到一个”sources”数组中,我们就能很轻易地合成这些图像到PDF中。

from PIL import Image
import os

def combine_imgs_pdf(folder_path, pdf_file_path):
    """
    合成文件夹下的所有图片为pdf

    Args:
        folder_path (str): 源文件夹
        pdf_file_path (str): 输出路径
    """
    files = os.listdir(folder_path)
    png_files = []
    sources = []
    for file in files:
        if 'png' in file or 'jpg' in file:
            png_files.append(folder_path + file)
    png_files.sort()

    output = Image.open(png_files[0])
    png_files.pop(0)
    for file in png_files:
        png_file = Image.open(file)
        if png_file.mode == "RGB":
            png_file = png_file.convert("RGB")
        sources.append(png_file)
    output.save(pdf_file_path, "pdf", save_all=True, append_images=sources)

if __name__ == "__main__":
    folder = r"G:\证件\\"
    pdfFile = r"G:\证件\身份证.pdf"
    combine_imgs_pdf(folder, pdfFile)

这样,只要将你的证件照都放在一个文件夹中,运行这个Python代码,它就能自动将这些证件合成到一个PDF中,并输出到你指定的路径。非常简单方便。

有需要的小伙伴,刚开那这份代码去试一下吧!在Python实用宝典后台回复 合成pdf 就能下载啦!

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python超好用的命令行参数工具—Click

Click 是一个简洁好用的Python模块,它能用尽量少的代码实现漂亮的命令行界面。它不仅开箱即用、还能支持高度自定义的配置。

一个简单的示例如下:

import click

@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
              help='The person to greet.')
def hello(count, name):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo(f"Hello {name}!")

if __name__ == '__main__':
    hello()

效果如下:

可见这个模块的强大之处,你只需要在对应的函数上加几个装饰器,就能实现带提示符的命令行界面的创建,相当方便。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install click

2.基本使用

如文首所示的例子一样,@click.option 是最基本的选项,它既可以设定参数默认值,也可以设定必须传入参数:

@click.command()
@click.option('--n', default=1) # 设定了默认值
def dots(n):
    click.echo('.' * n)
    

@click.command()
@click.option('--n', required=True, type=int) # 设定必须传入参数值
def dots(n):
    click.echo('.' * n)

如果你设置了必须传入相关参数,那么在没传入参数的情况下,效果是这样的:

当然,它还支持设定多种参数别名,比如下面的 –from 和 -f 是等效的:

@click.command()
@click.option('--from', '-f', 'from_')
@click.option('--to', '-t')
def reserved_param_name(from_, to):
    click.echo(f"from {from_} to {to}")

3.多值参数

如果你的选项需要多个参数,Click也能帮你实现这个需求。

@click.command()
@click.option('--pos', nargs=2, type=float)
def findme(pos):
    a, b = pos
    click.echo(f"{a} / {b}")

可见,通过配置nargs参数,你可以将用户传递的值存入元组,并在代码中解包这个元组拿到所有的值。

效果如下:

你还可以配置一个参数叫 multiple,这个参数可以让你接受N个值:

@click.command()
@click.option('--message', '-m', multiple=True)
def commit(message):
    click.echo(' '.join(message))

效果如下:

4.其他功能

你还可以使用Click来计数,这个使用非常罕见:

@click.command()
@click.option('-v', '--verbose', count=True)
def log(verbose):
    click.echo(f"Verbosity: {verbose}")

效果如下:

布尔标志

此外,Click还带有布尔标志功能,你可以直接使用 “/” 来标志参数为二选一参数,函数中直接就会拿到布尔型的变量:

import sys

@click.command()
@click.option('--shout/--no-shout', default=False)
def info(shout):
    rv = sys.platform
    if shout:
        rv = rv.upper() + '!!!!111'
    click.echo(rv)

效果如下:

选择选项

你可以直接限定用户的输入范围:

@click.command()
@click.option('--hash-type',
              type=click.Choice(['MD5', 'SHA1'], case_sensitive=False))
def digest(hash_type):
    click.echo(hash_type)

提示文本

在文首提到的例子中,输出了个 “You name:” 的提示,其实是 option 中的prompt参数控制的:

@click.command()
@click.option('--name', prompt='Your name please')
def hello(name):
    click.echo(f"Hello {name}!")

好了,Click的功能就介绍到这里,他还有许多高级的用法,比如动态默认值、回调函数等等,大家可以通过官方文档了解这些高级功能的使用方法:

https://click.palletsprojects.com/en/8.0.x/options/#name-your-options

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

FreqTrade—又强又简单的Python加密货币自动交易机器人

Freqtrade 是一个用 Python 编写的免费开源加密货币交易机器人。它旨在支持所有主要交易所并通过 Telegram 或 webUI 进行控制。功能包含回测、绘图和资金管理工具以及通过机器学习的策略优化。

目前支持的交易所:

特性:

  •  基于 Python 3.8+:适用于任何操作系统 – Windows、macOS 和 Linux。
  •  持久性:持久性是通过 sqlite 实现的。
  •  Dry-run:不花钱运行机器人。
  •  回测:模拟买入/卖出策略。
  •  通过机器学习进行策略优化:使用机器学习通过真实的交易所数据优化买入/卖出策略参数。
  •  边缘头寸规模计算您的胜率、风险回报率、最佳止损位并在为每个特定市场建立头寸之前调整头寸规模。
  •  白名单加密货币:选择你要交易的加密货币或使用动态白名单。
  •  黑名单加密货币:选择你想要避免的加密货币。
  •  内置 WebUI:内置 Web UI 来管理你的机器人。
  •  可通过 Telegram管理:使用 Telegram 管理机器人。
  •  以法定货币显示盈亏:以法定货币显示你的盈亏。
  •  表现状态报告:提供你当前交易的表现状态。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

在Linux/MacOS下,三行命令就能完成安装:

git clone -b develop https://github.com/freqtrade/freqtrade.git
cd freqtrade
./setup.sh --install

如果你无法克隆此项目,请在Python实用宝典公众号后台回复:freqtrade 下载。

Windows环境下打开Cmd(开始—运行—CMD),输入命令安装依赖:

git clone https://github.com/freqtrade/freqtrade.git
cd freqtrade
# 安装ta-lib
pip install build_helpers/TA_Lib-0.4.24-cp38-cp38-win_amd64.whl
pip install -r requirements.txt
pip install -e .
freqtrade

请注意,此处安装ta-lib时项目方提供了python3.8/3.9/3.10,其他Python版本请自行搜索下载。

输入freqtrade时,显示以下信息说明安装成功:

(freqtrade) D:\CODE\trader\freqtrade>freqtrade
2022-02-17 19:40:50,174 - freqtrade - ERROR - Usage of Freqtrade requires a subcommand to be specified.
To have the bot executing trades in live/dry-run modes, depending on the value of the `dry_run` setting in the config, run Freqtrade as `freqtrade trade [options...]`.
To see the full list of options available, please use `freqtrade --help` or `freqtrade <command> --help`.

2.Freqtrade 快速开始

下面教你如何开发一个简单的交易策略。

一个策略文件往往包含这些东西:

  • 指标
  • 购买规则
  • 卖出规则
  • 建议最低投资回报率
  • 强烈推荐止损

Freqtrade使用 Pandas 作为基础数据结构,它底层的OHLCV都是以Dataframe的格式存储的。

Dataframe数据流中每一行数据代表图表上的一根K线,最新的K线始终是数据库中最后一根。

> dataframe.head()
                       date      open      high       low     close     volume
0 2021-11-09 23:25:00+00:00  67279.67  67321.84  67255.01  67300.97   44.62253
1 2021-11-09 23:30:00+00:00  67300.97  67301.34  67183.03  67187.01   61.38076
2 2021-11-09 23:35:00+00:00  67187.02  67187.02  67031.93  67123.81  113.42728
3 2021-11-09 23:40:00+00:00  67123.80  67222.40  67080.33  67160.48   78.96008
4 2021-11-09 23:45:00+00:00  67160.48  67160.48  66901.26  66943.37  111.39292

Pandas 提供了计算指标的快速方法。为了从这种速度中受益,建议不要使用循环,而是使用矢量化方法。

矢量化操作在整个数据范围内执行计算,因此,与遍历每一行相比,在计算指标时要快得多。

dataframe.loc[(dataframe['rsi'] > 30), 'buy'] = 1

类似于上面这样的赋值方法,会自动设置rsi大于30的数据的buy列的值为1。

买入规则

def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
    """
    Based on TA indicators, populates the buy signal for the given dataframe
    :param dataframe: DataFrame populated with indicators
    :param metadata: Additional information, like the currently traded pair
    :return: DataFrame with buy column
    """
    dataframe.loc[
        (
            (qtpylib.crossed_above(dataframe['rsi'], 30)) &  # Signal: RSI crosses above 30
            (dataframe['tema'] <= dataframe['bb_middleband']) &  # Guard
            (dataframe['tema'] > dataframe['tema'].shift(1)) &  # Guard
            (dataframe['volume'] > 0)  # Make sure Volume is not 0
        ),
        'buy'] = 1

    return dataframe

请注意,一定要不修改并返回”open”, “high”, “low”, “close”, “volume”列,这些是基础行情数据,如果返回错误的数据将可能会导致一些奇怪数据的产生。

如上所示的方法中,符合条件的数据的buy值会被设为1代表买入,否则为0或nan值。

卖出规则

def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
    """
    Based on TA indicators, populates the sell signal for the given dataframe
    :param dataframe: DataFrame populated with indicators
    :param metadata: Additional information, like the currently traded pair
    :return: DataFrame with buy column
    """
    dataframe.loc[
        (
            (qtpylib.crossed_above(dataframe['rsi'], 70)) &  # Signal: RSI crosses above 70
            (dataframe['tema'] > dataframe['bb_middleband']) &  # Guard
            (dataframe['tema'] < dataframe['tema'].shift(1)) &  # Guard
            (dataframe['volume'] > 0)  # Make sure Volume is not 0
        ),
        'sell'] = 1
    return dataframe

与买入类似,这里不赘述了。

最小投资回报率

在类中增加这个初始化变量,能控制投资回报率:

minimal_roi = {
    "40": 0.0,
    "30": 0.01,
    "20": 0.02,
    "0": 0.04
}

上述配置意味着:

  • 只要达到 4% 的利润就卖出
  • 达到 2% 利润时卖出(20 分钟后生效)
  • 达到 1% 利润时卖出(30 分钟后生效)
  • 交易未亏损时卖出(40 分钟后生效)

此处的计算包含费用。

要完全禁用 ROI,请将其设置为一个非常高的数字:

minimal_roi = {
    "0": 100
}

虽然从技术上讲并没有完全禁用,但一旦交易达到 10000% 利润,它就会卖出。

止损

强烈建议设置止损,以保护资金免受不利的剧烈波动。

设置 10% 止损的示例:

stoploss = -0.10

一个完整代码如下:

# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file
# --- Do not remove these libs ---
from re import A
import numpy as np  # noqa
import pandas as pd  # noqa
from pandas import DataFrame

from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
                                IStrategy, IntParameter)

# --------------------------------
# 你自己所需要的模块放在这里
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib


# This class is a sample. Feel free to customize it.
class SampleStrategy(IStrategy):
    """
    This is a sample strategy to inspire you.
    More information in https://www.freqtrade.io/en/latest/strategy-customization/
    You can:
        :return: a Dataframe with all mandatory indicators for the strategies
    - Rename the class name (Do not forget to update class_name)
    - Add any methods you want to build your strategy
    - Add any lib you need to build your strategy
    You must keep:
    - the lib in the section "Do not remove these libs"
    - the methods: populate_indicators, populate_buy_trend, populate_sell_trend
    You should keep:
    - timeframe, minimal_roi, stoploss, trailing_*
    """
    # Strategy interface version - allow new iterations of the strategy interface.
    # Check the documentation or the Sample strategy to get the latest version.
    INTERFACE_VERSION = 2

    # 设定最小投资回报
    minimal_roi = {
        "60": 0.01,
        "30": 0.02,
        "0": 0.04
    }

    # 止损
    stoploss = -0.10

    # 指标参数
    buy_rsi = IntParameter(low=1, high=50, default=30, space='buy', optimize=True, load=True)
    sell_rsi = IntParameter(low=50, high=100, default=70, space='sell', optimize=True, load=True)

    # K线时间
    timeframe = '5m'

    # 在新K线出现时执行
    process_only_new_candles = False

    # These values can be overridden in the "ask_strategy" section in the config.
    use_sell_signal = True
    sell_profit_only = False
    ignore_roi_if_buy_signal = False

    # 预准备K线数
    startup_candle_count: int = 30

    # 下单类型
    order_types = {
        'buy': 'limit',
        'sell': 'limit',
        'stoploss': 'market',
        'stoploss_on_exchange': False
    }

    # 订单有效时间(gtc: 除非取消否则一直有效)
    order_time_in_force = {
        'buy': 'gtc',
        'sell': 'gtc'
    }

    plot_config = {
        'main_plot': {
            'tema': {},
            'sar': {'color': 'white'},
        },
        'subplots': {
            "MACD": {
                'macd': {'color': 'blue'},
                'macdsignal': {'color': 'orange'},
            },
            "RSI": {
                'rsi': {'color': 'red'},
            }
        }
    }

    def informative_pairs(self):
        """
        Define additional, informative pair/interval combinations to be cached from the exchange.
        These pair/interval combinations are non-tradeable, unless they are part
        of the whitelist as well.
        For more information, please consult the documentation
        :return: List of tuples in the format (pair, interval)
            Sample: return [("ETH/USDT", "5m"),
                            ("BTC/USDT", "15m"),
                            ]
        """
        return []

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Adds several different TA indicators to the given DataFrame
        Performance Note: For the best performance be frugal on the number of indicators
        you are using. Let uncomment only the indicator you are using in your strategies
        or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
        :param dataframe: Dataframe with data from the exchange
        :param metadata: Additional information, like the currently traded pair
        :return: a Dataframe with all mandatory indicators for the strategies
        """

        # Momentum Indicators
        # ------------------------------------

        dataframe['adx'] = ta.ADX(dataframe)
        dataframe['rsi'] = ta.RSI(dataframe)
        stoch_fast = ta.STOCHF(dataframe)
        dataframe['fastd'] = stoch_fast['fastd']
        dataframe['fastk'] = stoch_fast['fastk']

        # MACD
        macd = ta.MACD(dataframe)
        dataframe['macd'] = macd['macd']
        dataframe['macdsignal'] = macd['macdsignal']
        dataframe['macdhist'] = macd['macdhist']

        # MFI
        dataframe['mfi'] = ta.MFI(dataframe)

        # Bollinger Bands
        bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
        dataframe['bb_lowerband'] = bollinger['lower']
        dataframe['bb_middleband'] = bollinger['mid']
        dataframe['bb_upperband'] = bollinger['upper']
        dataframe["bb_percent"] = (
            (dataframe["close"] - dataframe["bb_lowerband"]) /
            (dataframe["bb_upperband"] - dataframe["bb_lowerband"])
        )
        dataframe["bb_width"] = (
            (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"]
        )

        # Parabolic SAR
        dataframe['sar'] = ta.SAR(dataframe)

        # TEMA - Triple Exponential Moving Average
        dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9)

        hilbert = ta.HT_SINE(dataframe)
        dataframe['htsine'] = hilbert['sine']
        dataframe['htleadsine'] = hilbert['leadsine']

        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Based on TA indicators, populates the buy signal for the given dataframe
        :param dataframe: DataFrame populated with indicators
        :param metadata: Additional information, like the currently traded pair
        :return: DataFrame with buy column
        """
        dataframe.loc[
            (
                # Signal: RSI crosses above 30
                (qtpylib.crossed_above(dataframe['rsi'], self.buy_rsi.value)) &
                (dataframe['tema'] <= dataframe['bb_middleband']) &  # Guard: tema below BB middle
                (dataframe['tema'] > dataframe['tema'].shift(1)) &  # Guard: tema is raising
                (dataframe['volume'] > 0)  # Make sure Volume is not 0
            ), 'buy'] = 1

        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Based on TA indicators, populates the sell signal for the given dataframe
        :param dataframe: DataFrame populated with indicators
        :param metadata: Additional information, like the currently traded pair
        :return: DataFrame with sell column
        """
        dataframe.loc[
            (
                # Signal: RSI crosses above 70
                (qtpylib.crossed_above(dataframe['rsi'], self.sell_rsi.value)) &
                (dataframe['tema'] > dataframe['bb_middleband']) &  # Guard: tema above BB middle
                (dataframe['tema'] < dataframe['tema'].shift(1)) &  # Guard: tema is falling
                (dataframe['volume'] > 0)  # Make sure Volume is not 0
            ), 'sell'] = 1
        return dataframe
        

3.启动机器人

启动机器人前还需要设定配置,配置模板在 config/examples 下面。

比如币安的配置,你还需要输入key和secret:

"exchange": {
        "name": "binance",
        "key": "your_exchange_key",
        "secret": "your_exchange_secret",
  	    ......
	}
}

启动机器人:

freqtrade trade --strategy AwesomeStrategy --strategy-path /some/directory  -c path/far/far/away/config.json

–strategy-path 指定策略文件位置

-c 参数指定配置文件位置

比如我把策略放在了user_data/strategies下,配置放在了config_examples下,这么输入命令启动机器人即可:

freqtrade trade --strategy SampleStrategy --strategy-path user_data/strategies  -c config_examples/config_binance.example.json

由于篇幅问题,本文只是介绍了freqtrade的冰山一角,在启动机器人前,一定要进行回测并进行模拟交易。它还有TG通知功能、WebUI管理界面,详细的使用方法大家可以参考官方教程:

https://www.freqtrade.io/en/stable/

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

为什么说Python大数据处理一定要用Numpy Array?

Numpy 是Python科学计算的一个核心模块。它提供了非常高效的数组对象,以及用于处理这些数组对象的工具。一个Numpy数组由许多值组成,所有值的类型是相同的。

Python的核心库提供了 List 列表。列表是最常见的Python数据类型之一,它可以调整大小并且包含不同类型的元素,非常方便。

那么List和Numpy Array到底有什么区别?为什么我们需要在大数据处理的时候使用Numpy Array?答案是性能。

Numpy数据结构在以下方面表现更好:

1.内存大小—Numpy数据结构占用的内存更小。

2.性能—Numpy底层是用C语言实现的,比列表更快。

3.运算方法—内置优化了代数运算等方法。

下面分别讲解在大数据处理时,Numpy数组相对于List的优势。

1.Numpy Array内存占用更小

适当地使用Numpy数组替代List,你能让你的内存占用降低20倍。

对于Python原生的List列表,由于每次新增对象,都需要8个字节来引用新对象,新的对象本身占28个字节(以整数为例)。所以,列表 list 的大小可以用以下公式计算:

64 + 8 * len(lst) + len(lst) * 28 字节

而使用Numpy,就能减少非常多的空间占用。比如长度为n的Numpy整形Array,它需要:

96 + len(a) * 8 字节

可见,数组越大,你节省的内存空间越多。假设你的数组有10亿个元素,那么这个内存占用大小的差距会是GB级别的。

2.Numpy Array速度更快、内置计算方法

运行下面这个脚本,同样是生成某个维度的两个数组并相加,你就能看到原生List和Numpy Array的性能差距。

import time
import numpy as np

size_of_vec = 1000

def pure_python_version():
    t1 = time.time()
    X = range(size_of_vec)
    Y = range(size_of_vec)
    Z = [X[i] + Y[i] for i in range(len(X)) ]
    return time.time() - t1

def numpy_version():
    t1 = time.time()
    X = np.arange(size_of_vec)
    Y = np.arange(size_of_vec)
    Z = X + Y
    return time.time() - t1


t1 = pure_python_version()
t2 = numpy_version()
print(t1, t2)
print("Numpy is in this example " + str(t1/t2) + " faster!")

结果如下:

0.00048732757568359375 0.0002491474151611328
Numpy is in this example 1.955980861244019 faster!

可以看到,Numpy比原生数组快1.95倍。

如果你细心的话,还能发现,Numpy array可以直接执行加法操作。而原生的数组是做不到这点的,这就是Numpy 运算方法的优势。

我们再做几次重复试验,以证明这个性能优势是持久性的。

import numpy as np
from timeit import Timer

size_of_vec = 1000
X_list = range(size_of_vec)
Y_list = range(size_of_vec)
X = np.arange(size_of_vec)
Y = np.arange(size_of_vec)

def pure_python_version():
    Z = [X_list[i] + Y_list[i] for i in range(len(X_list)) ]

def numpy_version():
    Z = X + Y

timer_obj1 = Timer("pure_python_version()", 
                   "from __main__ import pure_python_version")
timer_obj2 = Timer("numpy_version()", 
                   "from __main__ import numpy_version")

print(timer_obj1.timeit(10))
print(timer_obj2.timeit(10))  # Runs Faster!

print(timer_obj1.repeat(repeat=3, number=10))
print(timer_obj2.repeat(repeat=3, number=10)) # repeat to prove it!

结果如下:

0.0029753120616078377
0.00014940369874238968
[0.002683573868125677, 0.002754641231149435, 0.002803879790008068]
[6.536301225423813e-05, 2.9387418180704117e-05, 2.9171351343393326e-05]

可以看到,第二个输出的时间总是小得多,这就证明了这个性能优势是具有持久性的。

所以,如果你在做一些大数据研究,比如金融数据、股票数据的研究,使用Numpy能够节省你不少内存空间,并拥有更强大的性能。

参考文献:https://webcourses.ucf.edu/courses/1249560/pages/python-lists-vs-numpy-arrays-what-is-the-difference

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

教你使用 Python 获取Fredapi美国重要经济指标数据

美国的金融市场(主要是股市、债市和汇市)经常受到其国内各项经济数据影响而波动。不仅如此,这些经济数据甚至会影响远在太平洋对岸的港股和A股。因此对于世界经济火车头的美国,我们要有对其经济数据有一定程度的理解。

对于股市而言,几个比较重要的经济指标为:

1. 联储局公开市场委员会会议声明

联储局公开市场委员会(FOMC)是决定美国利率走向的主宰者,而利率是美国经济未来增长的最重要因素,它的变化都会令消费支出、公司利润、政府预算及股票债券和美元的价值都受到影响。

2.消费者物价指数 Consumer Price Index (CPI)

这个指标是市场上最瞩目的经济指标之一,通胀(缩)率是联储局决定是否加息的最主要参考指标,而消费者物价指数则是最重要的通胀(缩)指标。通胀(缩)会影响到民生、政府的财政政策和民间的所有经济活动。通胀(缩)对于投资市场来说是件非常可怕的事情,因为它制造了经济的不稳定性和不确定性,给股市会带来波动和风险。

3.生产者物价指数 Producer Price Index (PPI)

跟CPI一样,这个指标是预测通货膨胀的重要指标之一,不过它反映的是生产者这个环节,是在通胀转移到消费者之前的数据,也就是说它对通胀和利率政策更具前瞻性,尽管其对消费者的影响力不如CPI。

4.采购经理人指数 Purchasing Managers Index (PMI)

PMI是一项全面的经济指标,概括了美国整体制造业状况、就业及物价表现,是全球最受关注的经济资料之一。采购经理人指数为每月第一个公布的重要数据,加上其所反映的经济状况较为全面,因此市场十分重视数据所反映的具体结果。在一般意义上讲采购经理人指数上升,会带来美元汇价上涨;采购经理人指数下降,会带来美元汇价的下跌。

5.非农就业数据 Non-farm Payrolls (NFP)

是美国非农业人口的就业数据,由美国劳工部每月公布一次,反应美国经济的趋势,数据好说明经济好转,数据差说明经济转坏。非农数据会影响美联储对美元的货币政策,经济差,美联储会倾向减息,美元贬值,经济好,美联储会倾向加息,美元升值。

本文将教你如何使用Python调用 FRED(Federal Reserve Economic Data) 数据库API获取以上相关数据。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

pip install fredapi

2.注册账户获取FredApi权限

为了能够获取FRED的数据,你需要先注册账号、然后申请一个API秘钥,完全免费,三分钟就能解决。

进入FRED主页:https://research.stlouisfed.org

右上角有一个『My Account』,点进去后,选择『Create New Account』申请 FRED 账号:

注册完成后,会跳转到会员页,点击左侧API Keys:

申请API秘钥:

申请完毕后就能获得一个API Key了。

3.通过接口获取Fredapi经济指标数据

FRED 数据量非常庞大,其分为大分类和大分类的子项目。大分类我们可以通过这样的代码获得:

import requests
import pandas as pd
import datetime as dt
def fetch_releases(api_key):
    """
    取得 FRED 大分类信息
    Args:
        api_key (str): 秘钥
    """
    r = requests.get('https://api.stlouisfed.org/fred/releases?api_key='+api_key+'&file_type=json', verify=True)
    full_releases = r.json()['releases']
    full_releases = pd.DataFrame.from_dict(full_releases)
    full_releases = full_releases.set_index('id')
    # full_releases.to_csv("full_releases.csv")
    return full_releases

导出为CSV后,你能看到所有的大分类ID及其说明。

每个大分类中有许多子项目,比如 355:Minimum Wage Rates 底下会有:
* FEDMINNFRWG:Nonfarm Workers Minimum Hourly Wage
* FEDMINFRMWG:Farm Workers Minimum Hourly Wage

每一个子项目也有一个专属的『子项目英文代码』,就是前面的那串英文字。

我们可以通过对大分类进行关键字搜索,获取我们文首提到的五个指标:

from fredapi import Fred
import requests
import numpy as np
import pandas as pd
import datetime as dt


def fetch_releases(api_key):
    """
    取得 FRED 大分类信息
    Args:
        api_key (str): 秘钥
    """
    r = requests.get('https://api.stlouisfed.org/fred/releases?api_key='+api_key+'&file_type=json', verify=True)
    full_releases = r.json()['releases']
    full_releases = pd.DataFrame.from_dict(full_releases)
    full_releases = full_releases.set_index('id')
    # full_releases.to_csv("full_releases.csv")
    return full_releases

  
def fetch_release_id_data(release_id):
    """
    按照分类ID获取数据

    Args:
        release_id (int): 大分类ID

    Returns:
        dataframe: 数据
    """
    econ_data = pd.DataFrame(index=pd.date_range(start='2000-01-01', end=dt.datetime.today(), freq='MS'))
    series_df = fred.search_by_release(release_id, limit=3, order_by='popularity', sort_order='desc')
    for topic_label in series_df.index:
        econ_data[series_df.loc[topic_label].title] = fred.get_series(topic_label, observation_start='2000-01-01', observation_end=dt.datetime.today())
    return econ_data


api_key = '填入你的API秘钥'

fred = Fred(api_key)

full_releases = fetch_releases(api_key)

keywords = ["producer price", "consumer price", "fomc", "manufacturing", "employment"]

for search_keywords in keywords:
    search_result = full_releases.name[full_releases.name.apply(lambda x: search_keywords in x.lower())]
    econ_data = pd.DataFrame(index=pd.date_range(start='2000-01-01', end=dt.datetime.today(), freq='MS'))

    for release_id in search_result.index:
        print("scraping release_id: ", release_id)
        econ_data = pd.concat([econ_data, fetch_release_id_data(release_id)], axis=1)
    econ_data.to_csv(f"{search_keywords}.csv")

上面就是完整的数据下载代码,如果你想直接获取脚本文件,请在Python实用宝典后台回复:FRED 下载。

填入你申请的 API 秘钥,运行脚本,就能获取我们想要的五个指标数据。会在当前文件夹下生成相应关键词的csv文件。比如 employment.csv 的内容如下:

里面包含了就业相关的许多数据,包括我们关注的非农数据等。

如果你想要更换关键词下载其他关键词的数据,也可以在keywords中进行增删。请注意,这里搜索必须使用小写单词。

获取数据只是第一步,最重要的是如何分析这些数据与股市的相关性。

德意志银行有一个研究发现历年来ISM(即PMI)指数的数值和标普500的同比增长数值是高度相关的。

类似于这样的数据分析切入点是非常有意思的,大家也可以尝试基于这些数据做一些自己的研究分析,说不定会有意外的发现。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

神器!Python 老旧照片的面部恢复模块—GFPGAN

老照片作为时光记忆的载体,不只是过去美好时光的传承者,同时也是每个人的情结和怀念的寄托。

随着时间的流逝,许多老照片都因为自然或人为原因,受到了侵蚀损坏,画面模糊、褪色、照片磨损严重等现象,甚至还有的因为保管不好导致照片面目全非。

今天的这个Python模块叫GFPGAN,它能够让这些老照片恢复原有的光泽,使用了GAN算法对照片进行修复,效果比其他同类模型都有更好的表现。本模块支持Python3.7+版本。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),输入命令安装依赖:

# 克隆项目
git clone https://github.com/TencentARC/GFPGAN.git
  
# 进入项目
cd GFPGAN

# 安装依赖
pip install basicsr
pip install facexlib
pip install -r requirements.txt
pip install realesrgan

# 安装程序
python setup.py develop

2.使用GFPGAN进行老照片面部恢复

GFPGAN模型需要通过数据集训练得到,由于训练需要使用的数据量和算力非常大,作者团队提供了许多预处理好的模型给普通用户下载,这样我们就能绕过训练这个步骤直接使用模型,下载地址如下:

https://github.com/TencentARC/GFPGAN/releases/download/v0.2.0/GFPGANCleanv1-NoCE-C2.pth

如果你无法访问GitHub,也可以在Python实用宝典后台回复:GFPGAN 下载。包含了本项目源代码及许多其他预训练好的模型,包括:

将想要使用的预训练模型放入 experiments/pretrained_models 文件夹下就可以开始使用了。

使用方法非常简单,进入项目目录后输入以下命令:

python inference_gfpgan.py --model_path experiments/pretrained_models/GFPGANv1.pth --test_path inputs/cropped_faces --save_root results

其中,各个参数的意义如下:

model_path: 使用的模型的位置。

test_path: 需要转换的老照片的路径。

save_root: 转换结果存放的路径。

效果如下:

可见其修复效果是非常优秀的,如果你们也有需要修复的老照片,可以尝试使用手机的照片扫描仪软件扫描后使用此模块修复。

3.微调模型

如果你对模型的输出结果不是很满意,你还可以基于作者团队给出的模型做微调。微调能实现以下目的:

1.如果你有更高质量的人脸数据,可以提高修复效果。

2.你可能需要对数据做一些微处理,比如美妆等。

微调流程如下:

1.准备好训练数据集:https://github.com/NVlabs/ffhq-dataset

2.下载预训练模型和其他你自己的数据,把它们放在 experiments/pretrained_models 文件夹里。我们公众号后台提供以下预训练模型:

  • 预训练的 StyleGAN2 模型:StyleGAN2_512_Cmul1_FFHQ_B12G4_scratch_800k.pth
  • FFHQ 位置:FFHQ_eye_mouth_landmarks_512.pth
  • 一个简单的 ArcFace 模型:arcface_resnet18.pth

3.根据自身需求,相应地修改配置文件 options/train_gfpgan_v1.yml。

4.输入命令训练:

python -m torch.distributed.launch --nproc_per_node=4 --master_port=22021 gfpgan/train.py -opt options/train_gfpgan_v1.yml --launcher pytorch

模型微调的难度比较大,可能会遇到不少问题,大家要善于利用搜索引擎解决问题。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

什么是强化学习?量化投资领域预测股票的效果如何?

强化学习是机器学习的方式之一,它与监督学习、无监督学习并列,是三种机器学习训练方法之一。

在围棋上击败世界第一的李世石的 AlphaGo、在《星际争霸2》中以 10:1 击败了人类顶级职业玩家的AlphaStar,他们都是强化学习模型。诸如此类的模型还有 AlphaGo Zero 等。

强化学习的原理非常简单,它非常像心理学中新行为主义派的斯金纳发现的操作性条件反射。

操作性条件反射是什么?当年斯金纳做了一个箱子,进行了两次实验。

第一次实验,箱子里放了一只饥饿的老鼠,在箱子的一边有一个可供按压的杠杆,在杠杆旁边有一个放置食物的小盒子。动物在箱内按下杠杆,食盒就会释放食物进入箱内,动物可以取食。结果:小鼠自发学会了按按钮。这是积极强化。

另一次实验是,每次小白鼠不按下按钮,则给箱子通电,小白鼠因此学会了按按钮以防自己遭受电击。这是消极强化(负向强化)。

这就是斯金纳发现的操作性条件反射,当行为得到奖励或惩罚时出现刺激,反过来控制这种行为。

强化学习与操作性条件反射有异曲同工之妙,以人类玩游戏为例,如果在游戏中采取某种策略购买某种类型的装备可以取得较高的得分,那么就会进一步“强化”这种策略,以期继续取得较好的结果。

网上有不少强化学习的例子,鉴于读者中对股票感兴趣的同学比较多,我们以股票预测为例,实验一下 wangshubRL-Stock 项目。

使用强化学习预测股价,需要在决策的时候采取合适的行动 (Action) 使最后的奖励最大化。与监督学习预测未来的数值不同,强化学习根据输入的状态(如当日开盘价、收盘价等),输出系列动作(例如:买进、持有、卖出),并对好的动作结果不断进行奖励,对差的动作结果不断进行惩罚,使得最后的收益最大化,实现自动交易。

下面就试一下这个强化学习项目,前往GitHub下载 RL-Stock

如果你无法使用GitHub,也可以在Python实用宝典公众号后台回复:股票强化学习1 下载全文完整代码,包括第三部分的多进程优化逻辑。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。

(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.

(可选2) 此外,推荐大家用VSCode编辑器来编写小型Python项目:Python 编程的最好搭档—VSCode 详细指南

请注意,由于TensorFlow版本限制,这个强化学习项目只支持 Python3 以上,Python3.6 及以下的版本,因此我建议使用Anaconda创建一个新的虚拟环境运行这个项目:

conda create -n rlstock python=3.6

另外,实测依赖需要改动 requirements.txt 的tensorflow-gpu版本至1.14:

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),进入 RL-Stock 项目文件夹输入命令安装依赖:

pip install -r requirements.txt

2.小试强化学习预测股票价格

运行RL-Stock项目前,需要下载数据。进入刚创建的虚拟环境,运行get_stock_data.py代码会自动下载数据到 stockdata 目录中:

python get_stock_data.py

如果你使用的是在Github上下载的代码而不是Python实用宝典后台改好的代码,请注意 get_stock_data.py 的第46行,必须对 row[“code_name”] 去除 * 号,否则Windows系统下可能会存在问题:

df_code.to_csv(f'{self.output_dir}/{row["code"]}.{row["code_name"].strip("*")}.csv', index=False)

数据下载完成后就可以运行 main.py 执行强化学习训练和测试,不过在训练之前,我们先简单了解下整个项目的输入状态、动作、和奖励函数。

输入状态(观测 Observation)

策略网络观测的就是一只股票的各类数据,比如开盘价、收盘价、成交量等,它可以由许多因子组成。为了训练时网络收敛,观测状态数据输入时必须要进行归一化,变换到 [-1, 1] 的区间内。RL-Stock输入的观测数据字段如下:

参数名称参数描述说明
date交易所行情日期格式:YYYY-MM-DD
code证券代码格式:sh.600000。sh:上海,sz:深圳
open今开盘价格精度:小数点后4位;单位:人民币元
high最高价精度:小数点后4位;单位:人民币元
low最低价精度:小数点后4位;单位:人民币元
close今收盘价精度:小数点后4位;单位:人民币元
preclose昨日收盘价精度:小数点后4位;单位:人民币元
volume成交数量单位:股
amount成交金额精度:小数点后4位;单位:人民币元
adjustflag复权状态不复权、前复权、后复权
turn换手率精度:小数点后6位;单位:%
tradestatus交易状态1:正常交易 0:停牌
pctChg涨跌幅(百分比)精度:小数点后6位
peTTM滚动市盈率精度:小数点后6位
psTTM滚动市销率精度:小数点后6位
pcfNcfTTM滚动市现率精度:小数点后6位
pbMRQ市净率精度:小数点后6位

动作 Action

共有买入卖出持有 3 种动作,定义动作(action)为长度为 2 的数组

  • action[0] 为操作类型;
  • action[1] 表示买入或卖出百分比;
动作类型 action[0]说明
1买入 action[1]
2卖出 action[1]
3持有

注意,当动作类型 action[0] = 3 时,表示不买也不抛售股票,此时 action[1] 的值无实际意义,网络在训练过程中,Agent 会慢慢学习到这一信息。Agent,实称代理,在我们的上下文中,你可以视其为策略。

奖励 Reward

奖励函数的设计,对强化学习的目标至关重要。在股票交易的环境下,最应该关心的就是当前的盈利情况,故用当前的利润作为奖励函数。

# profits
reward = self.net_worth - INITIAL_ACCOUNT_BALANCE
reward = 1 if reward > 0 else -100

为了使网络更快学习到盈利的策略,当利润为负值时,给予网络一个较大的惩罚 (-100)。

梯度策略

作者采用了基于策略梯度的PPO 算法,OpenAI 和许多文献已把 PPO 作为强化学习研究中首选的算法。PPO 优化算法 Python 实现参考 stable-baselines

数据集及自定义

在数据集上,作者使用了1990年至2019年11月作为训练集,2019年12月作为测试集。

1990-01-01 ~ 2019-11-292019-12-01 ~ 2019-12-31
训练集测试集

如果你要调整这个训练集和测试集的时间,可以更改 get_stock_data.py 的以下部分:

if __name__ == '__main__':
    # 获取全部股票的日K线数据
    
    # 训练集
    mkdir('./stockdata/train')
    downloader = Downloader('./stockdata/train', date_start='1990-01-01', date_end='2019-11-29')
    downloader.run()
	# 测试集
    mkdir('./stockdata/test')
    downloader = Downloader('./stockdata/test', date_start='2019-12-01', date_end='2019-12-31')
    downloader.run()

训练并测试

首先,我们尝试一下单一代码的训练和测试,修改main.py里的股票代码,比如我这里修改为601919中远海控:

if __name__ == '__main__':
    # multi_stock_trade()
    test_a_stock_trade('sh.601919')
    # ret = find_file('./stockdata/train', '601919')
    # print(ret)

运行下面的命令,执行此深度学习模型的训练和测试。

python main.py

训练完成后,会自动进行模拟操作测试集这20个交易日,然后会输出这20个交易日的测试结果:

------------------------------
Step: 20
Balance: 0.713083354256014
Shares held: 2060 (Total sold: 2392)
Avg cost for held shares: 5.072161917927474 (Total sales value: 12195.091008936648)
Net worth: 10930.56492977963 (Max net worth: 10930.56492977963)
Profit: 930.5649297796299
------------------------------
Step: 21
Balance: 0.713083354256014
Shares held: 2060 (Total sold: 2392)
Avg cost for held shares: 5.072161917927474 (Total sales value: 12195.091008936648)
Net worth: 10815.713083354256 (Max net worth: 10930.56492977963)
Profit: 815.713083354256

利润图如下:

然后我们看一下中远海控2019年12月的走势:

可以看到这个月的中远海控是一个上升趋势,一共上涨了12%,而这个模型捕捉到其中8%左右的利润,还是相当不错的。当然,凡事不能只看个体,下面我们修改下作者的源代码,试一下其在市场里的整体表现。

3.强化学习模型整体表现

由于作者原有的模型是单进程的计算,为了测试全市场的表现,我进行了多进程改造。

我将作者的训练及测试任务集成到一个函数中,并使用celery做并行:

@app.task
def multi_stock_trade(code):
    stock_file = find_file('./stockdata/train', str(code))
    if stock_file:
        try:
            profits = stock_trade(stock_file)
            with open(f'result/code-{code}.pkl', 'wb') as f:
                pickle.dump(profits, f)
        except Exception as err:
            print(err)

将测试集的测试周期改为最近一个月:

1990-01-01 ~ 2021-11-252021-11-26 ~ 2021-12-25
训练集测试集

开启redis-server 及 Celery Worker:

# redis-server 独占一个进程,所以需要另开一个窗口
celery -A tasks worker -l info

遍历所有的股票代码做并发测试:

files = os.listdir("stockdata/train")
files_test = os.listdir("stockdata/test")
all_files_list = list(set(files) & set(files_test))
for i in all_files_list:
    # 使用celery做并发
    code = ".".join(i.split(".")[:2])
    # multi_stock_trade.apply_async(args=(code,))
    multi_stock_trade(code)

再对生成的结果进行统计,测试结果如下:

对这个模型在2021-11-26到2021-12-25的测试结果表明,有40.8%的股票进行了交易并且获利,有49.9%的股票没有进行操作,有9.4%的股票进行了交易并亏损。平均每次交易利润为445元,作为一个测试策略,这个结果已经很不错了。

由于只是一个测试策略,这里就不做详细的风险分析了,实际上我们还需要观察这个策略的最大回撤率、夏普率等指标才能更好地评判此策略的好坏。

我认为这个项目还有很大的改造空间,原逻辑中只观察了OHLC等基本数据,我们还可以增加很多指标,比如基于Ta-lib,算出MACD、RSI等技术指标,再将其加入Observation中,让模型观察学习这些数据的特征,可能会有不错的表现。有兴趣的同学可以试一下,本文源代码存放于:

https://github.com/Ckend/pythondict-quant

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Pydantic — 强大的数据校验工具,比DRF快12倍

Pydantic 是一个使用Python类型注解进行数据验证和管理的模块。安装方法非常简单,打开终端输入:

pip install pydantic

它类似于 Django DRF 序列化器的数据校验功能,不同的是,Django里的序列化器的Field是有限制的,如果你想要使用自己的Field还需要继承并重写它的基类:

# Django 序列化器
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    author = models.CharField(max_length=32)
    publish = models.CharField(max_length=32)

而 Pydantic 基于Python3.7以上的类型注解特性,实现了可以对任何类做数据校验的功能:

# Pydantic 数据校验功能
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name = 'John Doe'
    signup_ts: Optional[datetime] = None
    friends: List[int] = []


external_data = {
    'id': '123',
    'signup_ts': '2019-06-01 12:22',
    'friends': [1, 2, '3'],
}
user = User(**external_data)
print(user.id)
print(type(user.id))
#> 123
#> <class 'int'>
print(repr(user.signup_ts))
#> datetime.datetime(2019, 6, 1, 12, 22)
print(user.friends)
#> [1, 2, 3]
print(user.dict())
"""
{
    'id': 123,
    'signup_ts': datetime.datetime(2019, 6, 1, 12, 22),
    'friends': [1, 2, 3],
    'name': 'John Doe',
}
"""

从上面的基本使用可以看到,它甚至能自动帮你做数据类型的转换,比如代码中的 user.id, 在字典中是字符串,但经过Pydantic校验器后,它自动变成了int型,因为User类里的注解就是int型。

当我们的数据和定义的注解类型不一致时会报这样的Error:

from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name = 'John Doe'
    signup_ts: Optional[datetime] = None
    friends: List[int] = []


external_data = {
    'id': '123',
    'signup_ts': '2019-06-01 12:222',
    'friends': [1, 2, '3'],
}
user = User(**external_data)
"""
Traceback (most recent call last):
  File "1.py", line 18, in <module>
    user = User(**external_data)
  File "pydantic\main.py", line 331, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for User
signup_ts
  invalid datetime format (type=value_error.datetime)
"""

即 “invalid datetime format”, 因为我传入的 signup_ts 不是标准的时间格式(多了个2)。

1.Pydantic 模型数据导出

通过Pydantic模型中自带的 json 属性方法,能让经过校验后的数据一行命令直接转成 json 字符串,如前文中的user对象:

print(user.dict())  # 转为字典
"""
{
    'id': 123,
    'signup_ts': datetime.datetime(2019, 6, 1, 12, 22),
    'friends': [1, 2, 3],
    'name': 'John Doe',
}
"""
print(user.json())  # 转为json
"""
{"id": 123, "signup_ts": "2019-06-01T12:22:00", "friends": [1, 2, 3], "name": "John Doe"}
"""

非常方便。它还支持将整个数据结构导出为 schema json,它能完整地描述整个对象的数据结构类型:

print(user.schema_json(indent=2))
"""
{
  "title": "User",
  "type": "object",
  "properties": {
    "id": {
      "title": "Id",
      "type": "integer"
    },
    "signup_ts": {
      "title": "Signup Ts",
      "type": "string",
      "format": "date-time"
    },
    "friends": {
      "title": "Friends",
      "default": [],
      "type": "array",
      "items": {
        "type": "integer"
      }
    },
    "name": {
      "title": "Name",
      "default": "John Doe",
      "type": "string"
    }
  },
  "required": [
    "id"
  ]
}
"""

2.数据导入

除了直接定义数据校验模型,它还能通过ORM、字符串、文件导入到数据校验模型:

比如字符串(raw):

from datetime import datetime
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name = 'John Doe'
    signup_ts: datetime = None
      
m = User.parse_raw('{"id": 123, "name": "James"}')
print(m)
#> id=123 signup_ts=None name='James'

此外,它能直接将ORM的对象输入,转为Pydantic的对象,比如从Sqlalchemy ORM:

from typing import List
from sqlalchemy import Column, Integer, String
from sqlalchemy.dialects.postgresql import ARRAY
from sqlalchemy.ext.declarative import declarative_base
from pydantic import BaseModel, constr

Base = declarative_base()


class CompanyOrm(Base):
    __tablename__ = 'companies'
    id = Column(Integer, primary_key=True, nullable=False)
    public_key = Column(String(20), index=True, nullable=False, unique=True)
    name = Column(String(63), unique=True)
    domains = Column(ARRAY(String(255)))


class CompanyModel(BaseModel):
    id: int
    public_key: constr(max_length=20)
    name: constr(max_length=63)
    domains: List[constr(max_length=255)]

    class Config:
        orm_mode = True


co_orm = CompanyOrm(
    id=123,
    public_key='foobar',
    name='Testing',
    domains=['example.com', 'foobar.com'],
)
print(co_orm)
#> <models_orm_mode.CompanyOrm object at 0x7f0bdac44850>
co_model = CompanyModel.from_orm(co_orm)
print(co_model)
#> id=123 public_key='foobar' name='Testing' domains=['example.com',
#> 'foobar.com']

从Json文件导入:

from datetime import datetime
from pathlib import Path
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name = 'John Doe'
    signup_ts: datetime = None
      
path = Path('data.json')
path.write_text('{"id": 123, "name": "James"}')
m = User.parse_file(path)
print(m)

从pickle导入:

import pickle
from datetime import datetime
from pydantic import BaseModel

pickle_data = pickle.dumps({
    'id': 123,
    'name': 'James',
    'signup_ts': datetime(2017, 7, 14)
})
m = User.parse_raw(
    pickle_data, content_type='application/pickle', allow_pickle=True
)
print(m)
#> id=123 signup_ts=datetime.datetime(2017, 7, 14, 0, 0) name='James'

3.自定义数据校验

你还能给它增加 validator 装饰器,增加你需要的校验逻辑:

from pydantic import BaseModel, ValidationError, validator


class UserModel(BaseModel):
    name: str
    username: str
    password1: str
    password2: str

    @validator('name')
    def name_must_contain_space(cls, v):
        if ' ' not in v:
            raise ValueError('must contain a space')
        return v.title()

    @validator('password2')
    def passwords_match(cls, v, values, **kwargs):
        if 'password1' in values and v != values['password1']:
            raise ValueError('passwords do not match')
        return v

    @validator('username')
    def username_alphanumeric(cls, v):
        assert v.isalnum(), 'must be alphanumeric'
        return v

上面,我们增加了三种自定义校验逻辑:

1.name 必须带有空格

2.password2 必须和 password1 相同

3.username 必须为字母

让我们试试这三个校验是否成功实现:

user = UserModel(
    name='samuel colvin',
    username='scolvin',
    password1='zxcvbn',
    password2='zxcvbn',
)
print(user)
#> name='Samuel Colvin' username='scolvin' password1='zxcvbn' password2='zxcvbn'

try:
    UserModel(
        name='samuel',
        username='scolvin',
        password1='zxcvbn',
        password2='zxcvbn2',
    )
except ValidationError as e:
    print(e)
    """
    2 validation errors for UserModel
    name
      must contain a space (type=value_error)
    password2
      passwords do not match (type=value_error)
    """

可以看到,第一个UserModel里的数据完全没有问题,通过校验。

第二个UserModel里的数据,由于name存在空格,password2和password1不一致,无法通过校验。

4.性能表现

这是最令我惊讶的部分,Pydantic 比 Django-rest-framework 还快了12.3倍:

PackageVersionRelative PerformanceMean validation time
pydantic1.7.393.7μs
attrs + cattrs20.3.01.5x slower143.6μs
valideer0.4.21.9x slower175.9μs
marshmallow3.10.02.4x slower227.6μs
voluptuous0.12.12.7x slower257.5μs
trafaret2.1.03.2x slower296.7μs
schematics2.1.010.2x slower955.5μs
django-rest-framework3.12.212.3x slower1148.4μs
cerberus1.3.225.9x slower2427.6μs

而且他们的所有基准测试代码都是开源的,你可以在下面这个Github链接找到:

https://github.com/samuelcolvin/pydantic/tree/master/benchmarks

如果你的网络无法访问GitHub,请关注Python实用宝典公众号后台回复Pydantic获取。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典