[{"content":"前言 《穷查理宝典》并非传统的投资教科书，而是一位智者关于认知、决策和生活方式的深度总结。理解这本书的精华，关键在于跳出零散的金句，把握查理·芒格思维体系的核心。\n一、书籍精华概览 1. 建立\u0026quot;多元思维模型\u0026quot;的框架（普世智慧） 芒格认为，如果你的头脑中只有孤立的知识，就无法真正理解任何东西，甚至会陷入\u0026quot;铁锤人倾向\u0026quot;——在只有铁锤的人看来，每个问题都像钉子。\n核心精要：\n你必须学习各学科（数学、物理、生物、心理、会计、经济等）中最重要、最基本的原理（约80-90个），并将它们悬挂在头脑中的一个框架上，形成思维模型的格栅 在面对复杂问题时，交叉使用不同学科的模型进行分析，才能看清事物的本质 2. 人类误判心理学（识别思维陷阱） 芒格指出，人类的大脑在进化过程中存在许多缺陷，导致我们在无意识中犯下系统性的错误。\n核心精要：\n他总结了25种人类误判倾向（如：奖励超级反应倾向、避免不一致性倾向、社会认同倾向等） Lollapalooza效应：当数种心理倾向共同作用于同一个方向时，会产生极端的后果（好坏皆然）。理解这些倾向不仅能帮助你避免被骗，还能让你在管理和说服他人时更有效率 3. 逆向思考（反过来想，总是反过来想） 这是芒格最独特的思维武器。他效仿代数学家雅各比，通过研究\u0026quot;如何失败\u0026quot;来学习\u0026quot;如何成功\u0026quot;。\n核心精要：\n如果你想在生活中获得幸福，首先要研究人生如何才能变得痛苦；要研究企业如何做强，首先要研究企业是如何衰败的 金句：\u0026ldquo;我只想知道将来我会死在什么地方，这样我就不去那儿了。\u0026rdquo; 4. 价值投资与性格修养 芒格将投资视为一种性格和修养的体现，而非单纯的数学计算。\n投资哲学：\n主张集中投资，耐心等待\u0026quot;好球\u0026quot;出现，一旦看准机会就狠狠下注 比起廉价的平庸公司，他更倾向于以合理的价格购买拥有可持续竞争优势（护城河）的优质企业 终身学习：\n芒格自比为\u0026quot;长了两条腿的书\u0026quot;，他认为只有成为学习机器，每天睡觉前比早晨聪明一点，才能在激烈竞争中获胜 道德责任：\n他推崇中国传统的\u0026quot;士大夫精神\u0026quot;，强调做人要正直，要通过让自己配得上来获得想要的东西 二、25种人类误判倾向详解 查理·芒格系统性地总结了人类在进化过程中形成的25种容易误导认知的倾向。理解这些倾向不仅能帮助我们避免犯错，还能在商业和生活中更有效地做出决策。\n1. 奖励和惩罚超级反应倾向 激励机制具有超级威力，人们往往会为了获取回报而做出不道德的行为，并利用\u0026quot;激励机制引起的偏见\u0026quot;为自己的行为寻找正当理由。\n2. 喜欢/热爱倾向 这种天生的倾向促使人们忽略热爱对象的缺点，并为了爱而扭曲事实。\n3. 讨厌/憎恨倾向 与喜欢倾向相反，它促使人们忽略讨厌对象的优点，并为了仇恨扭曲认知。\n4. 避免怀疑倾向 人类大脑天生有一种尽快作出决定以消除怀疑的倾向，这通常由困惑或压力引发。\n5. 避免不一致性倾向 为了节省运算空间，大脑倾向于保留原有的习惯、结论和身份，不愿作出改变。\n6. 好奇心倾向 强烈的好奇心能推动知识发展，并帮助人们减少其他心理倾向造成的糟糕后果。\n7. 康德式公平倾向 人们在现代社会普遍表现出并期待从他人那里得到某种\u0026quot;黄金法则\u0026quot;式的公平。\n8. 艳羡/妒忌倾向 这是植根于占有欲的强烈倾向，常引起仇恨和伤害，但在心理学教材中常被忽视。\n9. 回馈倾向 人类有以德报德、以牙还牙的倾向，虽能促进合作，但也容易被某些有心机的人操控。\n10. 受简单联想影响的倾向 人们容易受单纯联想的误导，例如认为价格高代表质量好，或因过去的偶然成功而盲目乐观。\n11. 简单的、避免痛苦的心理否认 当现实太过痛苦而无法承受时，大脑会扭曲事实直到它们变得可以承受。\n12. 自视过高的倾向 人们常高估自己、自己的配偶或私人物品（即禀赋效应），并容易产生\u0026quot;确认偏见\u0026quot;。\n13. 过度乐观倾向 即便在形势大好时，人们也会表现出不理性的过度乐观。\n14. 被剥夺超级反应倾向 失去已有的好处或错失即将拥有的好处，所带来的痛苦远大于得到同等好处的快乐。\n15. 社会认同倾向 在感到困惑或压力时，人们会倾向于自动模仿周边人的思考和行动方式。\n16. 对比错误反应倾向 大脑感知的是鲜明的对比而非精确数值，导致人们在面对逐渐恶化的趋势时反应迟钝。\n17. 压力影响倾向 突然的重压会导致人体肾上腺素激增，甚至引发彻底的思维紊乱。\n18. 错误衡量易得性倾向 大脑倾向于高估容易得到的东西的重要性，忽视更重要但难以获取的事实。\n19. 不用就忘倾向 所有技能若不经常操练都会退化，明智的人会利用检查清单来防止遗忘。\n20. 化学物质错误影响倾向 酒精、毒品等化学物质对行为和认知具有毁灭性的破坏力。\n21. 衰老—错误影响倾向 年龄增长自然会导致认知衰退，尽管保持快乐的学习能在一定程度上延缓这一过程。\n22. 权威—错误影响倾向 人类天生有追随领袖的倾向，这可能导致在权威人物犯错时人们也跟着犯错。\n23. 废话倾向 人类天生就有啰里啰唆、制造废话的本事，这常会干扰他人专注做正经事。\n24. 重视理由倾向 人们天生热爱准确的认知，当命令或知识配有合理解释时，更容易被接受和理解。\n25. Lollapalooza倾向 当上述数种倾向共同作用于同一个方向时，会产生极其极端的后果。这是芒格最重视的效应，它解释了为什么某些事件会产生远超预期的巨大影响。\n三、阅读建议 如果你在阅读《穷查理宝典》时感到\u0026quot;一头雾水\u0026quot;，以下是几个实用的建议：\n1. 先读芒格私人书单 了解芒格的知识地图，理解他如何构建跨学科的思维框架。这将帮助你更好地理解他的思想来源。\n2. 重点研读\u0026quot;人类误判心理学\u0026quot; 这是全书含金量最高的部分（第三讲）。仔细阅读25种误判倾向，并思考它们在日常生活和工作中的表现。\n3. 结合实际案例思考 书中的每个概念都配有实际案例。尝试将这些概念应用到你熟悉的领域，比如投资、管理、或个人决策。\n4. 建立自己的思维模型清单 在阅读过程中，记录下你认为最重要的思维模型，并尝试在实践中应用它们。\n四、核心金句摘录 \u0026ldquo;反过来想，总是反过来想。\u0026rdquo;\n\u0026ldquo;我只想知道将来我会死在什么地方，这样我就不去那儿了。\u0026rdquo;\n\u0026ldquo;获得智慧是一种道德责任。\u0026rdquo;\n\u0026ldquo;要得到你想要的某样东西，最可靠的办法是让你自己配得上它。\u0026rdquo;\n\u0026ldquo;如果你的头脑中只有一个思维模型，你就会扭曲现实以符合你的思维模型。\u0026rdquo;\n\u0026ldquo;我这辈子遇到的聪明人没有不每天阅读的——没有，一个都没有。\u0026rdquo;\n五、总结 《穷查理宝典》的核心价值在于提供了一套系统的思维框架和认知工具。通过理解：\n多元思维模型的重要性 25种人类误判倾向 逆向思考的方法 终身学习的重要性 你就掌握了芒格智慧的精髓。这不仅是一本投资书，更是一本关于如何更明智地生活和决策的指南。\n芒格的智慧告诉我们：真正的智慧不在于掌握多少知识，而在于如何将这些知识整合成一个有机的思维系统，并在实践中不断完善和应用。只有这样，我们才能在复杂多变的世界中做出更明智的决策，过上更有意义的生活。\n","date":"2026-01-20T16:00:00+08:00","permalink":"https://eryk-github-io.pages.dev/2026/01/20/%E7%A9%B7%E6%9F%A5%E7%90%86%E5%AE%9D%E5%85%B8%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0%E8%8A%92%E6%A0%BC%E7%9A%84%E6%99%BA%E6%85%A7%E7%B2%BE%E5%8D%8E/","title":"《穷查理宝典》读书笔记：芒格的智慧精华"},{"content":"devtoolset介绍 devtoolset是为 Scientific Linux CERN 5 和 6 平台上的开发人员提供的产品。使用 Software Collections 框架，根据 UNIX 文件系统层次结构标准的建议，将一组额外的工具安装到 /opt 目录中。这些工具由用户使用提供的 scl 实用程序按需启用。\ndevtoolset与gcc的版本对应关系 devtoolset-3对应gcc4.9.x版本 devtoolset-4对应gcc5.x.x版本 devtoolset-6对应gcc6.x.x版本 devtoolset-7对应gcc7.x.x版本 devtoolset-8对应gcc8.x.x版本 devtoolset-9对应gcc9.x.x版本\n安装步骤 由于devtoolset-3版本太老官方仓库已经不再提供安装，所以从需要先从其他网站更新仓库地址，具体更新和安装步骤如下\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cd /etc/yum.repos.d wget https://copr.fedorainfracloud.org/coprs/rhscl/devtoolset-3-el7/repo/epel-7/rhscl-devtoolset-3-el7-epel-7.repo yum install devtoolset-3-toolchain scl enable devtoolset-3 bash gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/opt/rh/devtoolset-3/root/usr/libexec/gcc/x86_64-redhat-linux/4.9.2/lto-wrapper Target: x86_64-redhat-linux Configured with: ../configure --prefix=/opt/rh/devtoolset-3/root/usr --mandir=/opt/rh/devtoolset-3/root/usr/share/man --infodir=/opt/rh/devtoolset-3/root/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --enable-languages=c,c++,fortran,lto --enable-plugin --with-linker-hash-style=gnu --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.9.2-20150212/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.9.2-20150212/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux Thread model: posix gcc version 4.9.2 20150212 (Red Hat 4.9.2-6) (GCC) 参考 https://linux.web.cern.ch/devtoolset/\nhttps://copr.fedorainfracloud.org/coprs/rhscl/devtoolset-3-el7/\nhttps://blog.csdn.net/zzhongcy/article/details/89950976\n","date":"2021-10-29T11:34:00Z","permalink":"https://eryk-github-io.pages.dev/2021/10/29/centos-7%E5%AE%89%E8%A3%85%E5%90%84%E7%A7%8D%E7%89%88%E6%9C%AC%E7%9A%84devtoolset-3/","title":"CentOS 7安装各种版本的devtoolset-3"},{"content":"下载Redis源码 1 git clone -b 6.2 https://github.com/redis/redis.git CLion导入Redis 启动IDE之后弹出如下弹窗点击OK\n等导入项目加载完成之后，在IDE中打开Makefileb并点击第三行的绿色箭头执行make操作\n运行完成之后会在src目录下出现编译好的.o文件，比如redis-cli.o和redis-server.o\n运行redis-server debug 模式 找到Edit Configurations后打开，在Target中选择reids-server，Executable中找到src/redis-server，设置启动参数指定redis.conf\n设置好之后运行，提示如下错误\n安装pkg-config 1 brew install pkg-config 再次运行redis-server的debug模式启动成功\n参考 https://www.modb.pro/db/73281\nhttps://zhuanlan.zhihu.com/p/339812402\nhttps://www.jianshu.com/p/904b44911ab9\nhttps://github.com/LHRchina/redis\n","date":"2021-10-15T11:34:00Z","permalink":"https://eryk-github-io.pages.dev/2021/10/15/%E5%9C%A8macbook%E4%B8%AD%E5%AF%BC%E5%85%A5redis%E6%BA%90%E7%A0%81%E5%B9%B6%E8%B0%83%E8%AF%95/","title":"在MacBook中导入Redis源码并调试"},{"content":"不可追踪的加密数字货币 门罗币（Monero）是一种分散的加密货币，意味着它是由用户网络操作的安全数字现金。事务通过分布式协商一致确认，然后在区块链上进行不可更改的记录。 第三方不需要被信任来保证你的门罗币（Monero）的安全。\n如何使用电脑CPU如何挖矿 非常简单，就两步：\n下载并创建门罗币钱包 下载并设置挖矿程序 步骤1：下载并创建门罗币钱包 在门罗币官网下载Windows钱包，地址是：https://downloads.getmonero.org/gui/win64\n解压缩并运行monero-wallet-gui.exe，按照下图红框位置语言选择中文，然后根据提示进行下一步操作，模式选择简易模式\n创建一个新的钱包，记录保管好助记种子，万一密码忘记了可以通过助记词找回账户密码\n下一步输入密码之后就创建好了钱包，登录钱包看到钱包页面。\n复制钱包地址，类似如下字符串：\n1 43WufLh9YvQU8UoPxFcgK8gAxMcCigmnPWSBGf6jvTY6URjkhPUCuBKHx5nTQR7HZR7UCnug1zdkWL9dppqDfzgnF64zV1i 这样就完成了钱包的创建\n步骤2：下载并设置挖矿程序 下载门罗币挖矿程序，这里使用的是比较流行的xmrig，官网地址：https://github.com/xmrig/xmrig/\n挖矿程序下载地址：https://github.com/xmrig/xmrig/releases/download/v6.10.0/xmrig-6.10.0-msvc-win64.zip\n找到并设置如下两项\n1 2 \u0026#34;url\u0026#34;: \u0026#34;mine.c3pool.com:15555\u0026#34;, \u0026#34;user\u0026#34;: \u0026#34;43WufLh9YvQU8UoPxFcgK8gAxMcCigmnPWSBGf6jvTY6URjkhPUCuBKHx5nTQR7HZR7UCnug1zdkWL9dppqDfzgnF64zV1i\u0026#34;, 第一个url是矿池地址，这里使用的c3pool，第二个user是门罗币钱包地址，请使用上一步自己创建的钱包地址替换。\n设置好点击目录下的start.cmd文件就开启挖矿程序了。\n查看挖矿进度 通过以下网址可以查看挖矿进度，https://c3pool.com/cn/\n打开网址后在网页中输入自己的钱包地址，就可以看到类似如下界面\n","date":"2021-04-25T11:34:00Z","permalink":"https://eryk-github-io.pages.dev/2021/04/25/%E6%95%B0%E5%AD%97%E8%B4%A7%E5%B8%81%E9%97%A8%E7%BD%97%E5%B8%81cpu%E6%8C%96%E7%9F%BF%E6%95%99%E7%A8%8B/","title":"数字货币门罗币cpu挖矿教程"},{"content":"通常我使用笔记本电脑编写程序代码，而数据采集是由一台服务器进行，为了方便开发调试，需要把程序部署到服务器上运行。这时候就用到了pycharm的远程部署调试功能。\n1. 配置远程服务器 在pycharm中Perferences -\u0026gt; Build, Execution, Deployment -\u0026gt; Deployment菜单下添加远程服务器配置，Type选择SFTP这样可以通过ssh方式将代码传到服务器上\n![image-20210306171219402](/Users/eryk/Library/Application Support/typora-user-images/image-20210306171219402.png)\n填写服务器地址、端口（ssh服务端口默认是22）、用户名和密码，密码如果配置了免秘钥登录可以选择“OpenSSH config and authentication”方式，否则选择password输入密码就可以，设置好之后点Test Connection验证如果可以连通则会弹出如下截图：\n![image-20210306171534805](/Users/eryk/Library/Application Support/typora-user-images/image-20210306171534805.png)\n说明已经可以连上服务器了，默认部署在服务器登录用户的根目录下，如有需要部署在其他位置可以修改Root path参数。设置好之后点ok保存配置就完成了第一步。\n2. 设置代码自动上传 ![image-20210306172025658](/Users/eryk/Library/Application Support/typora-user-images/image-20210306172025658.png)\n打开菜单栏中Tools -\u0026gt; Deployment，勾选“Automatic Upload(always)”，这样每次保存代码有更新都会上传到服务器上，始终保持服务器和本地代码一致。点击“Brown Remote Host” 可以在pycharm 右侧弹出标签栏中看到远程服务器上目录内容。\n3. 配置远程Python Interpreter 在pycharm中Perferences -\u0026gt; Project: 项目名 -\u0026gt; Project Interpreter，在右侧点击添加，如下步骤1所示位置\n![image-20210306173647677](/Users/eryk/Library/Application Support/typora-user-images/image-20210306173647677.png)\n弹出“Add Python Interpreter” 对话框，在 “Existing server configuration” 中选择刚添加的服务器，如上图步骤2所示。然后点next，\n接下来需要设置服务器上Python所在路径和程序自动同步的位置，这里建议和之前deploy保持一致。\n点击Finish就可以看到已经添加好了Remote Python，如下图所示\n4. 运行Python远程代码 编写测试代码，新建mian.py，代码内容是输出当前程序所在路径，测试一下程序是否在服务器上运行\n1 2 3 import os print(os.system(\u0026#39;pwd\u0026#39;)) 设置“Edit Configuration” ，将Python interpreter设置为刚添加的远程服务器的python，运行代码，输出如下说明已经在远程服务器上运行成功了。\n","date":"2021-03-06T16:55:00Z","permalink":"https://eryk-github-io.pages.dev/2021/03/06/%E4%BD%BF%E7%94%A8pycharm%E8%BF%9C%E7%A8%8B%E9%83%A8%E7%BD%B2%E8%BF%90%E8%A1%8Cpython%E7%A8%8B%E5%BA%8F/","title":"使用pycharm远程部署运行python程序"},{"content":"missingno提供了一个灵活且易于使用的丢失数据可视化工具和实用程序的小型工具集，使您可以快速直观地概述数据集的完整性（或缺乏完整性）。只需pip install missingno就可以开始使用了\nmissingno包含了4种类型图示：\nMetrix：msno.matrix无效矩阵是一种数据密集显示图，可以直观的看到各个column缺失数据分布情况，这种可视化图示最多可以容纳50个column，超过此范围的标签开始重叠或变得不可读。 Bar：msno.bar是按列对无效性数据的简单可视化：\nHeatmap：数据列之前缺失相关性分析图，展示了一个变量的存在或不存在对另一个变量的存在有多强烈的影响\nDendrogram：通过树状图，您可以更全面地关联变量完成，揭示比Heatmap中可见的成对趋势更深的趋势。与metrix图一样，在这种配置下最多只能显示50个带标签的列。但是，树状图只需翻转到水平配置即可更优雅地处理超大型数据集。\n参考 https://github.com/ResidentMario/missingno\n","date":"2020-12-27T22:53:00Z","permalink":"https://eryk-github-io.pages.dev/2020/12/27/pandas%E7%BC%BA%E5%A4%B1%E5%80%BC%E5%8F%AF%E8%A7%86%E5%8C%96%E5%88%86%E6%9E%90%E6%A8%A1%E5%9D%97missingno/","title":"Pandas缺失值可视化分析模块：missingno"},{"content":"最近重读了这本经典的金融投资类书籍，把其中精华部分摘录的下来，除了摘录的部分，第三章内容介绍的交易日志介绍了如何给一笔交易打分也不错，作者让我们更多的关注一笔交易的好坏，而不仅仅是盯住账户盈亏，这样日积月累交易技术才会精进。以下是本书精华部分，介绍了多种卖出的目的与技术。\n第二部分 如何卖出 卖出策略分为下列三种：\n止盈卖出 保护性止损卖出 在止盈或止损之间卖出，因为市场状况变化了，我们接下来不再希望持有这只股票 第四章 止盈 你的止盈价是多少—这只股票可能会涨多少？ 股票跌多少你才会相信你的买入决策是错误的，并止损。 这只股票的期望损益比是多少？潜在的收益和风险之间的关系是什么？ 对波段交易者来说，使用移动平均线和通道组合是设置目标价的好方法。如果要设立长期交易的盈利目标，就需要查看长期的支撑和压力在哪里。\n移动平均线卖出 周线图中，在价值之下买入，把盈利目标设置在价值区，这个方法非常好用。三重过滤网系统要求在周K线做出战略决策，在日K线实施，日线是做战术性买入或卖出的时间框架。\n使用通道技术卖出 如果使用通道技术给交易设定了盈利目标，但后来你觉得反弹高度会更高一些怎么办？你可能会持有多长时间？尽管价格有时候会反弹得很高，它容易让人放弃先前的决定而持有更长时间，但经验告诉我不要持有头寸时间过久。\n如果价格比你设定的初始目标价低一些，你会获利了结吗？当这个问题摆在我面前的时候，我就等价格创新高失败的那天以收盘价卖出，或者在次日开盘后不久卖出。\n压力位卖出 移动平均线卖出法适用于股票超卖后的反弹，通道卖出法适合短线交易者使用，这些方法可以用于短期波段交易。短期交易的波动幅度相对于长期交易者来说太小，我们曾把长线交易者称为投资者，但世界在变快，每个人又都是交易者。长线交易者的交易周期以月甚至年来衡量，这需要更大的盈利目标。猎鹿的人与猎兔子的人不同，猎鹿的人需要一杆大枪。\n支撑和压力区的存在为长线交易者提供了盈利目标。我们把大量交易发生过的地方作为压力或支撑区，这样就很容易知道相对于压力或支撑，价格目前所处的位置。\n每开始一次交易，你都应该有两个目标：赚钱和变成更好的交易者。你不一定每次都达到第一个目标，但必须达到第二个目标。如果没有从交易中学到什么，你就是在浪费时间和金钱。\n第五章 止损 每次交易都应该设定止损。请务必遵循这个简单的规则：在确切地知道止损位置之前，不要交易。入场前你必须做出这个决策，当然你还应该确立一个盈利目标以计算损益比。没有目标的交易无异于赌博。\n铁三角止损 设立止损的首要目的是避免情势不利时损失超过预期，第二个目的是保护浮盈，第三个目的毫无疑问是控制与资金管理有密切关系的总资金亏损。\n风险控制工作的过程分三个步骤：\n分析并设定止损位，通过入场价与止损价之间的距离计算每股风险损失值。\n假如准备以18美元/每股的价格买入股票，分析后发现如果股价跌破17美元就改变看多观点，所以你决定把保护性止损设在16.89美元。每股风险值是1.11美元，如果加上滑点的话每股风险值会更高一点，但是1.11美元已经是一个合理的估计值了。\n运用资金管理规则确定单次交易的最大损失额度以及交易者所能承受的风险值。\n假设你的交易账户有5万美元，并遵循2%的资金管理规则。这意味着你每次交易的最大风险值是1000美元，这个风险值也比较适中，实际中不少人希望止损小于1%。\n根据1和2中的数据计算可购入的最大股票数量。\n这样就可以计算得出单次交易所能购入的最大股票数量。如果单次交易最大风险值是1000美元，每股允许的风险值是1.11美元，最大的交易股数应该小于900股；另外这1000美元中必须包括交易佣金和滑点。还有一点，没有人规定你必须交易最大可购入的股数，如果你觉得风险仍然太大，可以交易比这个数量更少的股票。如果你对这只18美元的股票抱有很大期望，就应该把止损空间设得大一些，比如在15.89美元，然后每股允许的风险值将会是2.11美元；单次交易的最大损失值不变，因此你最多可购入的股票数量就只有470股了。\n市价止损和限价止损 市价指令可以保证执行，但不能保证价格；限价指令保证价格但不能保证一定会执行。\n硬止损和软止损 硬止损是下到市场中的止损指令，软止损是交易者牢记的止损价格，只要市场价格达到止损价格，就立即下单。\n糟糕的止损位 关于止损的最糟糕的认识是，只要价格低于最近的最低价就立即止损\n止损设在前低上：减少滑点 把止损点设在前期低点上而不是低于前期低点一个Tick的地方。看了很多图表后我发现，很少有股票在价格跌到前低的时候停下脚步，它们往往跌破前低。正常情况下，价格不是到不了前低就是跌破前低，这表明把止损设在低于前低一个Tick的位置上对交易安全没有帮助，所以我开始把止损设在前低的位置上。\n尼克止损法 寻找大多数人设置止损的价格，然后找出跌破该价格的K线，并把止损设在两个次低价中较低的那个价格之下。这种紧随的设置止损方法非常适合短期波段交易，试图抓住底部是很危险的，而这样一个紧随性止损却会很好地保护账户，这就像告诉市场，要么来打我止损（反正止损不大），要么就给我涨。\n使用宽幅止损的时机 交易周期影响止损大小，较短时间框架内的交易止损必须小，而长周期框架的交易要求止损大一些。短期时间框架内的价格运动先于长期时间框架内的价格运动。\n移动止损 可以用K线组合的低点作为新的止损点，比如把止损移动到最近三根K线最低价的位置（但决不要和交易方向相反）。 可以使用周期非常短的移动平均线，并把均线值作为追踪止损值。 可以使用枝形灯止损法，市场每次创新高都从最高点起算，以特定的距离向上移动止损，这个距离的计算应基于ATR（真实波幅）。只要股价创新高，就把止损向上移一定距离，这种方式就像从天花板上挂一盏枝形灯（本方法已经在《走进我的交易室》中介绍过）。 抛物线止损。 安全区止损。 回撤比例止损。 时间止损，如果在一定时间内价格没有变化就止损。比如做一笔日内交易，如果股价在10～15分钟内明显没有按照你的预期变化，那么最好了结这次交易；如果做一笔波段交易并预计股价会持续好几个交易日，但是一周过去了股价仍在横盘整理。这表明价格没有确认你的判断，安全的做法是赶紧出局。 抛物线止损指标 今日SAR=前一日SAR+AF×（EP–前一日SAR）\n其中，今日SAR=今日止损价；\nEP=当前交易中到达过的极点，如果看多，EP就表示近期明显的低点；如果看空，EP就表示近期明显的高点；\nAF=加速因子。\n交易的第一天加速因子等于0.02，表示你必须把止损设在近期极值的2%处；只要价格创下新高或新低，加速因子就增加0.02，加速因子的最大值是0.2。\n抛物线系统在趋势行情中运行很好，但在震荡行情中却频频失灵。另外，不要在计算机自动交易中使用这个系统。\n安全区止损 安全区止损的理念来源于金融市场中的信号和噪音，如果趋势是信号，那么回调就是噪音。\n我们可以用多种方法定义趋势，比较简单且直接的方法是用价格与22天EMA的相对位置来定义趋势。在涨势中我们把噪音定义为今日价格中低于前一天低点的部分，这部分与趋势相反；如果是跌势我们把噪音定义为今日价格中高于前一天高点的部分。交易者需要决定测量噪音的回测期的长度，回测期不能太长但必须对交易有实质意义，只需日线图中最近一个月左右的数据就可以了\n如果在上涨趋势中把所有噪音部分标出来并汇总，除以噪音发生的总次数，就得出回测期的噪音均值，它反映了当前上升趋势中的平均噪音水平。把止损设得太近容易弄巧成拙，所以要把止损设在远离噪音均值的地方，用噪音均值乘以平均噪音系数（初始值为2，也可用大于2的数值），用昨天最低价减去上面的这个计算结果就得出了止损应该设置的地方。如果今天的最低值比昨天低就不移动止损，这种方法只允许将止损向上移动。\n下跌趋势与上涨趋势的规则相反。当22日EMA均线显示目前处于下跌趋势，计算回测期噪音均值并乘以系数，用昨日最高价加上上述数值，就得出今日的止损设置位置。同样，止损只向下移动不向上移动。\n波幅减少追踪止损法 如果市场即将疯狂并大幅移动，我自然愿意留在市场中。我使用通道设置价格目标，通道宽度的正常值是2.7倍标准差。如果我想在价格达到目标价以后使用追踪止损，我会把止损设在1.7倍标准差的地方，只要价格继续沿着正常通道运动我就一直持有，但只要收盘价在1.7倍标准差这个通道内我就离场。通道宽度可以用修改通道参数的方法来修改。\n如何决定在价格达到盈利目标时是获利了结还是使用追踪止损？ 如果价格到达盈利目标并且看到顶背离信号，我就不用追踪止损；只要看到不利的价格运动，比如长上影伴随巨大的成交量，我会在盈利目标位获利了结；如果市场运行良好，并且底部一次比一次高，我就使用追踪止损方法。在价格到达盈利目标后，只有看到足够积极的价格信号我才会使用追踪止损。\n盈利目标转换为追踪止损的使用频率是多少？ 我在2/3的交易中都使用这种方法，但用得不是很好。有时候刚刚设定了追踪止损，5分钟后就被扫出局。大约有一半时间追踪止损法给我带来比原先更多的利润，大的获益极少，主要来自大行情中。\n","date":"2020-12-20T22:34:00Z","permalink":"https://eryk-github-io.pages.dev/2020/12/20/%E6%8A%95%E8%B5%84%E8%91%97%E4%BD%9C%E5%93%81%E8%AF%BB1%E4%BB%A5%E4%BA%A4%E6%98%93%E4%B8%BA%E7%94%9Fii%E5%8D%96%E5%87%BA%E7%9A%84%E8%89%BA%E6%9C%AF%E4%B8%AD%E7%9A%84%E7%B2%BE%E5%8D%8E/","title":"投资著作品读1：《以交易为生II:卖出的艺术》中的精华"},{"content":"关于MultiIndex的资料并不太多，官方文档链接请点这里查看。\n最近在使用MultiIndex时遇到的一个问题，先描述一下数据格式。我使用MultiIndex DataFrame来存储股票未来N天的收益率，变量命名为returns，数据样例如下，columns 1d和5d分别表示未来1天和5天的股票收益率，index为MultiIndex，第一级索引为日期，第二级索引为股票代码。\n1 2 3 4 5 6 7 8 9 10 11 12 1d 5d 2005-01-04 000001.XSHE -0.009202 0.010736 000002.XSHE 0.036053 0.045541 000004.XSHE 0.020896 0.068657 000005.XSHE 0.023474 0.098592 000006.XSHE 0.014286 0.178571 ... ... ... 2020-12-11 688600.XSHG NaN NaN 688777.XSHG NaN NaN 688788.XSHG NaN NaN 688981.XSHG NaN NaN 689009.XSHG NaN NaN 对returns用start=\u0026lsquo;2020-01-01\u0026rsquo;、end=\u0026lsquo;2020-12-11\u0026rsquo;起止时间做了截断处理，代码片段如下：\n1 2 returns_index = returns.index.get_level_values(level=0) returns = returns.loc[(returns_index \u0026gt; pd.to_datetime(start)) \u0026amp; (returns_index \u0026lt; pd.to_datetime(end))] 这样获取的数据是从2020年开始的，但是使用returns.index.levels[0]发现数据还是从2005年开始的\n1 2 3 4 5 6 7 8 9 returns.index.levels[0] DatetimeIndex([\u0026#39;2005-01-04\u0026#39;, \u0026#39;2005-01-05\u0026#39;, \u0026#39;2005-01-06\u0026#39;, \u0026#39;2005-01-07\u0026#39;, \u0026#39;2005-01-10\u0026#39;, \u0026#39;2005-01-11\u0026#39;, \u0026#39;2005-01-12\u0026#39;, \u0026#39;2005-01-13\u0026#39;, \u0026#39;2005-01-14\u0026#39;, \u0026#39;2005-01-17\u0026#39;, ... \u0026#39;2020-11-30\u0026#39;, \u0026#39;2020-12-01\u0026#39;, \u0026#39;2020-12-02\u0026#39;, \u0026#39;2020-12-03\u0026#39;, \u0026#39;2020-12-04\u0026#39;, \u0026#39;2020-12-07\u0026#39;, \u0026#39;2020-12-08\u0026#39;, \u0026#39;2020-12-09\u0026#39;, \u0026#39;2020-12-10\u0026#39;, \u0026#39;2020-12-11\u0026#39;], dtype=\u0026#39;datetime64[ns]\u0026#39;, length=3875, freq=None) 想了想，应该是由于index索引不可变，这里需要重建MultiIndex DataFrame，需要用到pandas.MultiIndex.remove_unused_levels() 方法先删除掉index里多余的信息，然后再重新创建MultiIndex DataFrame，代码如下：\n1 2 3 4 tmp = returns.index.remove_unused_levels() tmp = returns.index.remove_unused_levels() returns = pd.DataFrame(returns, tmp) returns.index.levels[0] 1 2 3 4 5 6 7 8 DatetimeIndex([\u0026#39;2020-01-02\u0026#39;, \u0026#39;2020-01-03\u0026#39;, \u0026#39;2020-01-06\u0026#39;, \u0026#39;2020-01-07\u0026#39;, \u0026#39;2020-01-08\u0026#39;, \u0026#39;2020-01-09\u0026#39;, \u0026#39;2020-01-10\u0026#39;, \u0026#39;2020-01-13\u0026#39;, \u0026#39;2020-01-14\u0026#39;, \u0026#39;2020-01-15\u0026#39;, ... \u0026#39;2020-11-27\u0026#39;, \u0026#39;2020-11-30\u0026#39;, \u0026#39;2020-12-01\u0026#39;, \u0026#39;2020-12-02\u0026#39;, \u0026#39;2020-12-03\u0026#39;, \u0026#39;2020-12-04\u0026#39;, \u0026#39;2020-12-07\u0026#39;, \u0026#39;2020-12-08\u0026#39;, \u0026#39;2020-12-09\u0026#39;, \u0026#39;2020-12-10\u0026#39;], dtype=\u0026#39;datetime64[ns]\u0026#39;, length=228, freq=None) 看输出结果已经获取到了正确的时间范围内的数据。\n","date":"2020-12-13T16:54:00Z","permalink":"https://eryk-github-io.pages.dev/2020/12/13/pandas-multiindex%E7%B4%A2%E5%BC%95%E4%BD%BF%E7%94%A8%E9%97%AE%E9%A2%98/","title":"Pandas MultiIndex索引使用问题"},{"content":"今天遇到一个Pandas索引生成的问题，需要根据股票日频数据生成1分钟间隔的index，想了3个方法来生成：\n方法1: 如果有1分钟bar数据的话可以直接读取数据获取index值，可惜没有哈\n方法2: pandas.date_range，这个方法可以生成一个时间序列，设置参数freq=\u0026lsquo;1min\u0026rsquo; ，但是这样生成的结果包含了非交易时间段的数据，运行试了下速度也比较慢。\n方法3: 两个list循环，第一个list是日期数据，第二个list是交易时间段的1分钟间隔数据，这个办法虽然笨点但是运行速度还挺快的，具体方法如下：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import itertools import tushare as ts import pandas as pd pro = ts.pro_api() df = ts.pro_bar(ts_code=\u0026#39;000001.SZ\u0026#39;, adj=\u0026#39;hfq\u0026#39;, start_date=\u0026#39;20200101\u0026#39;, end_date=\u0026#39;20201209\u0026#39;) df.index = pd.to_datetime(df[\u0026#39;trade_date\u0026#39;]) df.sort_index(inplace=True) times = [d.strftime(\u0026#39;%H:%M:%S\u0026#39;) for d in pd.date_range(\u0026#39;09:30:00\u0026#39;, \u0026#39;11:30:00\u0026#39;, closed=\u0026#39;right\u0026#39;, freq=(\u0026#39;{}min\u0026#39;.format(1)))] + [ d.strftime(\u0026#39;%H:%M:%S\u0026#39;) if d.strftime(\u0026#39;%H:%M:%S\u0026#39;) != \u0026#39;13:00:00\u0026#39; else \u0026#39;11:30:00\u0026#39; for d in pd.date_range(\u0026#39;13:00:00\u0026#39;, \u0026#39;15:00:00\u0026#39;, closed=\u0026#39;right\u0026#39;, freq=(\u0026#39;{}min\u0026#39;.format(1)))] tmp = [str(item[0])[:10] + \u0026#39; \u0026#39; + item[1] for item in itertools.product(list(df.index), times)] min1_index = pd.to_datetime(tmp) print(min1_index) 输出结果如下：\n1 2 3 4 5 6 7 8 9 10 11 12 DatetimeIndex([\u0026#39;2020-01-02 09:31:00\u0026#39;, \u0026#39;2020-01-02 09:32:00\u0026#39;, \u0026#39;2020-01-02 09:33:00\u0026#39;, \u0026#39;2020-01-02 09:34:00\u0026#39;, \u0026#39;2020-01-02 09:35:00\u0026#39;, \u0026#39;2020-01-02 09:36:00\u0026#39;, \u0026#39;2020-01-02 09:37:00\u0026#39;, \u0026#39;2020-01-02 09:38:00\u0026#39;, \u0026#39;2020-01-02 09:39:00\u0026#39;, \u0026#39;2020-01-02 09:40:00\u0026#39;, ... \u0026#39;2020-12-09 14:51:00\u0026#39;, \u0026#39;2020-12-09 14:52:00\u0026#39;, \u0026#39;2020-12-09 14:53:00\u0026#39;, \u0026#39;2020-12-09 14:54:00\u0026#39;, \u0026#39;2020-12-09 14:55:00\u0026#39;, \u0026#39;2020-12-09 14:56:00\u0026#39;, \u0026#39;2020-12-09 14:57:00\u0026#39;, \u0026#39;2020-12-09 14:58:00\u0026#39;, \u0026#39;2020-12-09 14:59:00\u0026#39;, \u0026#39;2020-12-09 15:00:00\u0026#39;], dtype=\u0026#39;datetime64[ns]\u0026#39;, length=54480, freq=None) ","date":"2020-12-09T17:13:00Z","permalink":"https://eryk-github-io.pages.dev/2020/12/09/%E4%B8%80%E4%B8%AApandas%E7%B4%A2%E5%BC%95%E7%94%9F%E6%88%90%E7%9A%84%E5%B0%8F%E9%97%AE%E9%A2%98/","title":"一个Pandas索引生成的小问题"},{"content":"介绍 pyfolio是由Quantopian开发的Python库，用于对金融投资组合进行绩效和风险分析。它与Zipline开源回溯测试库配合使用良好。 pyfolio的核心是所谓的“tear sheet ”，它由各种单独的图组成，这些图提供了交易算法性能的全面图像展示。\n入门示例 这里以双均线策略来做演示，当20日均线上穿40日均线买入股票，当20日均线下穿40日均线则卖出股票，首先我们通过tushare获取股票历史数据\n1 2 3 4 5 6 7 8 9 import pandas as pd import numpy as np import tushare as ts import pyfolio as pf pro = ts.pro_api() df = ts.pro_bar(ts_code=\u0026#39;000001.SZ\u0026#39;, adj=\u0026#39;hfq\u0026#39;, start_date=\u0026#39;20150101\u0026#39;, end_date=\u0026#39;20191231\u0026#39;) df.index = pd.to_datetime(df[\u0026#39;trade_date\u0026#39;]) df.sort_index(inplace=True) 接下来生成策略信号\n1 2 3 4 5 6 7 8 9 10 11 df[\u0026#39;ma20\u0026#39;] = df[\u0026#39;close\u0026#39;].rolling(20).mean() df[\u0026#39;ma40\u0026#39;] = df[\u0026#39;close\u0026#39;].rolling(40).mean() # 计算20日均线和40日均线的距离 df[\u0026#39;diff\u0026#39;] = df[\u0026#39;ma20\u0026#39;] - df[\u0026#39;ma40\u0026#39;] # 当diff值大于0买入股票，当diff值小于0卖出股票 df[\u0026#39;signal\u0026#39;] = np.where(df[\u0026#39;diff\u0026#39;] \u0026gt; 0, 1, 0) df[\u0026#39;signal\u0026#39;] = np.where(df[\u0026#39;diff\u0026#39;] \u0026lt; 0, 0, df[\u0026#39;signal\u0026#39;]) # 计算策略每日收益，这里计算每日收益使用log函数，signal计算由于使用了当天的收盘价，所以需要shift 1天，否则会用到未来数据 df[\u0026#39;strategy\u0026#39;] = np.log(df[\u0026#39;close\u0026#39;] / df[\u0026#39;close\u0026#39;].shift(1)) * df[\u0026#39;signal\u0026#39;].shift(1) # 计算资产收益率 df[\u0026#39;equity\u0026#39;] = df[\u0026#39;strategy\u0026#39;].cumsum() + 1 展示资产收益率曲线，这里对股价做了归一化处理以便数据展示，可以看到双均线策略不仅跑赢股价，并且资金曲线回撤相对较小。\n1 2 df[\u0026#39;close_norm\u0026#39;] = df[\u0026#39;close\u0026#39;] / float(df[\u0026#39;close\u0026#39;][0]) df[[\u0026#39;close_norm\u0026#39;,\u0026#39;equity\u0026#39;]].plot(figsize=(12,6)) 上图看到的信息有限，接下来是使用pyfolio工具对投资回报进一步分析，代码如下:\n1 pf.create_full_tear_sheet(df[\u0026#39;strategy\u0026#39;], benchmark_rets=np.log(df[\u0026#39;close\u0026#39;] / df[\u0026#39;close\u0026#39;].shift(1))) 首先是返回汇总信息：\n介绍常用的几个指标：\nAnnual return：年化回报率 Cumulative returns: 累计收益率，是策略从开始执行到结束的总资产收益率。 Annual volatility：年化波动率 Sharpe ratio：夏普比率，一种非常流行的风险指标。它表示每单位风险（通过标准差衡量）的超额收益（超过无风险利率）。 Sortino ratio: 索提诺比率，Sharpe比率的修改版本，其中标准偏差由下行偏差代替。下行偏差仅衡量该系列的负波动性，严格来说是在称为最低可接受收益的预定水平以下。 Maximum drawdown ：最大跌幅—指示峰和谷之间的最大跌幅（以％表示） Tail ratio：对daily return的分布选取95分位和5分位，然后相除取绝对值。本质的含义就是赚取的return比亏钱的大多少倍。 Daily value at risk（daily Value-at-Risk ） 每日风险价值-另一个非常流行的风险指标。在这种情况下，这表明在95％的情况下，将头寸（投资组合）再保留1天，损失不会超过2.3％。 下图从各个角度对资产回报进行更详细的图表展示\n参考 https://quantopian.github.io/pyfolio/ https://zhuanlan.zhihu.com/p/118108419 https://towardsdatascience.com/the-easiest-way-to-evaluate-the-performance-of-trading-strategies-in-python-4959fd798bb3\n","date":"2020-11-29T09:53:00Z","permalink":"https://eryk-github-io.pages.dev/2020/11/29/quantopian%E6%8A%95%E8%B5%84%E7%BB%84%E5%90%88%E5%92%8C%E7%BB%A9%E6%95%88%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7pyfolio/","title":"Quantopian投资组合和绩效分析工具：Pyfolio"},{"content":"Quantopian是国外著名的量化交易平台，早期聚宽就是仿照这个网站开发的，算是这类平台的鼻祖了，可惜Quantopian最近刚宣布要停止运营了。Quantopian开发了许多优秀的开源项目，其中比较著名的有zipline、pyfolio和alphalens，zipline是事件驱动的回测引擎，Alphalens与Zipline开源回溯测试库以及Pyfolio配合使用，Pyfolio提供金融投资组合的绩效和风险分析。\nAlphalens主要功能是alpha因子的相关性统计数据和图表展示，包括：\nReturns Analysis Information Coefficient Analysis Turnover Analysis Grouped Analysis 下面通过一个例子来了解下Alphalens的主要用法，最重要的函数有两个:\nget_clean_factor_and_forward_returns：数据预处理，将因子数据，价格数据和组映射格式化为包含对齐的时间戳和资产代码的MultiIndex索引的DataFrame。返回的数据将被格式化为适合Alphalens函数的格式。因子数据格式是MultiIndex索引，level0是时间，level1是资产代码，数据值只有一列为因子值，数据格式如下图所示：\ncreate_full_tear_sheet: 生成全面的单因子分析和评估数据。\n通过tushare获取A股股票数据，并将结果处理成get_clean_factor_and_forward_returns参数要求的格式\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 import pandas as pd import tushare as ts pro = ts.pro_api() # 此接口获取的数据为未复权数据，回测建议使用后复权数据，这里为批量获取股票数据做了简化 df = pro.daily(ts_code=\u0026#39;000001.SZ,600000.SH\u0026#39;, start_date=\u0026#39;20200101\u0026#39;, end_date=\u0026#39;20201231\u0026#39;) df.index = pd.to_datetime(df[\u0026#39;trade_date\u0026#39;]) df.index.name = None df.sort_index(inplace=True) # MultiIndex，level0为日期，level1为股票代码，assets为get_clean_factor_and_forward_returns所需的因子数据格式 assets = df.set_index([df.index, df[\u0026#39;ts_code\u0026#39;]], drop=True) # column为股票代码，index为日期，值为股票收盘价 close = df.pivot_table(index=\u0026#39;trade_date\u0026#39;,columns=\u0026#39;ts_code\u0026#39;,values=\u0026#39;close\u0026#39;) close.index = pd.to_datetime(close.index) 生成的assets格式入下图所示，红框为index：\n生成的close格式如下图所示：\n接下来使用alphalens工具对数据进行分析，这里我们使用股票涨跌幅(字段名为pct_chg)作为因子数据\n1 2 3 4 5 from alphalens.utils import get_clean_factor_and_forward_returns from alphalens.tears import create_full_tear_sheet # 需要将pct_chg做shift处理，否则将使用未来数据 ret = get_clean_factor_and_forward_returns(assets[[\u0026#39;pct_chg\u0026#39;]].shift(2),close) create_full_tear_sheet(ret, long_short=False) 使用默认参数的情况下，ret将包含未来1、5、10日收益率，factor因子值，这里对应pct_chg列，factor_quantile为因子分组结果，默认会将因子分成5组，ret结果如图所示:\n调用create_full_tear_sheet会生成因子分析结果，包含分位数统计信息、收益率信息、分组平均收益率柱状图、所有收益率分布图、单信号组合构建收益率图等，截取部分数据图如下：\n以上就是样例全部内容，可以看到alphalens功能非常丰富，还需要继续深入学习了解。\n参考 http://quantopian.github.io/alphalens/\nhttps://www.quantopian.com/posts/alphalens-a-new-tool-for-analyzing-alpha-factors\n","date":"2020-11-20T09:22:00Z","permalink":"https://eryk-github-io.pages.dev/2020/11/20/quantopian%E5%8D%95%E5%9B%A0%E5%AD%90%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7alphalens/","title":"Quantopian单因子分析工具：Alphalens"},{"content":"大家也许有过这种经历，关注的某只股票突发利好消息预判会连续涨停，赶紧打开炒股软件准备下单，发现这只股票已经涨停了，而且是几十万手的大单封死，根本没机会下手，随后几天只能看着股票一个涨停接一个涨停的一路上涨，后悔下手太慢。这种情况还有办法上车吗，散户一般能想到的办法都没戏，但是可以试试下面这种办法，吃不到肉但也许能喝口汤。\nETF套利介绍 在介绍之前我们先了解下什么是ETF套利？ETF指的是交易型开放式指数基金，是一种在交易所上市交易，并且份额可以变动的一种开放式基金，它的手续与股票是完全一样的。由于一级市场和二级市场同时存在，不可避免会出现价格无法同步的显现，这种情况下就给一些机构跨市场套利提供了条件，而套利交易会让套利机会消失，让两个市场的价格差异得到控制，从而保证一级和二级市场价格的一致性。因为一级市场只能是机构投资者参与，所以我们一般的投资者是没办法进行ETF套利的。\n散户该如何操作呢 那我们怎么参与涨停股票的交易呢，办法很简单，可以找出持有我们要买入的涨停股的ETF基金，再看看基金持有的股票数量占基金的比重，找持有股票占比大的基金买入。一般基金持仓比较分散，每只股票持有数量从百分之零点几到百分之十几不等，而且优质股票往往被上百只基金同时持有，如何快速找到持有股票的基金和比重呢？\n操作实战 以天齐锂业为例，我们从东方财富网上可以找到机构持仓明细 http://data.eastmoney.com/zlsj/detail/2019-12-31-0-002466.html，可以看到有多种类型的基金，我们选择ETF基金，比如最近比较火的华夏中证5G通信主题ETF\n进入到该基金的页面 http://fundact.eastmoney.com/fundinfo/515050.html?fund=515050，可以查看该基金持有的前十大股票，第一名就是中兴通信，占比9.90%\n了解以上的数据源之后，我们可以写个python程序快速的找到某只股票的基金持仓及占比情况，源码如下：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import requests import execjs from bs4 import BeautifulSoup REQUEST_HEADER = { \u0026#39;User-Agent\u0026#39;: \u0026#39;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36\u0026#39;} def get_stock_fundlist(symbol, date=\u0026#39;2019-12-31\u0026#39;): \u0026#34;\u0026#34;\u0026#34; 查询股票被持有的基金及持仓占比 :param symbol: 股票代码，例如: SZ000001 :param date: 报告日期，例如：2019-12-31，2019-03-31 :return: \u0026#34;\u0026#34;\u0026#34; stock_url = \u0026#39;http://data.eastmoney.com/zlsj/detail.aspx?type=ajax\u0026amp;sr=-1\u0026amp;p=1\u0026amp;ps=1000\u0026amp;stat=0\u0026amp;code=%s\u0026amp;date=%s\u0026amp;rt=52763434\u0026#39; fund_url = \u0026#39;http://fund.eastmoney.com/f10/FundArchivesDatas.aspx?type=jjcc\u0026amp;code=%s\u0026amp;topline=15\u0026#39; web_source = requests.get(stock_url % (symbol[2:], date), headers=REQUEST_HEADER, timeout=5) js_obj = execjs.compile(web_source.content.decode(\u0026#39;gbk\u0026#39;)) results = js_obj.eval(\u0026#39;jsname\u0026#39;) if \u0026#39;data\u0026#39; not in results: return etf_list = [record[\u0026#39;SHCode\u0026#39;] for record in results[\u0026#39;data\u0026#39;] if record[\u0026#39;SHCode\u0026#39;].startswith(\u0026#39;5\u0026#39;)] results = {} for code in etf_list[:]: web_source = requests.get(fund_url % code, headers=REQUEST_HEADER, timeout=5) html_source = web_source.content.decode() html_source = html_source.split(\u0026#34;\\\u0026#34;\u0026#34;)[1] soup = BeautifulSoup(html_source, \u0026#39;lxml\u0026#39;) items = soup.select(\u0026#34;.tzxq\u0026#34;)[0].select(\u0026#39;tr\u0026#39;) for item in items[1:]: if symbol[2:] not in item.text: continue fields = item.select(\u0026#39;td\u0026#39;) record = [field.text.strip() for field in fields if field.text.strip() != \u0026#39;\u0026#39; and \u0026#39;变动\u0026#39; not in field.text] results[code] = record[3][:-1] break return sorted(results.items(), key=lambda kv: kv[1], reverse=True) if __name__ == \u0026#39;__main__\u0026#39;: print(get_stock_fundlist(\u0026#39;SZ000063\u0026#39;, \u0026#39;2019-12-31\u0026#39;)) 执行代码输出结果如下：\n1 [(\u0026#39;515050\u0026#39;, \u0026#39;9.90\u0026#39;), (\u0026#39;570007\u0026#39;, \u0026#39;6.87\u0026#39;), (\u0026#39;519668\u0026#39;, \u0026#39;6.52\u0026#39;), (\u0026#39;501062\u0026#39;, \u0026#39;5.37\u0026#39;), (\u0026#39;550002\u0026#39;, \u0026#39;5.13\u0026#39;), (\u0026#39;515000\u0026#39;, \u0026#39;5.10\u0026#39;), (\u0026#39;570006\u0026#39;, \u0026#39;5.08\u0026#39;), (\u0026#39;501028\u0026#39;, \u0026#39;4.81\u0026#39;), (\u0026#39;502013\u0026#39;, \u0026#39;4.33\u0026#39;), (\u0026#39;501015\u0026#39;, \u0026#39;4.26\u0026#39;), (\u0026#39;550015\u0026#39;, \u0026#39;4.22\u0026#39;), (\u0026#39;515580\u0026#39;, \u0026#39;4.19\u0026#39;), (\u0026#39;501026\u0026#39;, \u0026#39;4.19\u0026#39;), (\u0026#39;512970\u0026#39;, \u0026#39;3.94\u0026#39;), (\u0026#39;519929\u0026#39;, \u0026#39;3.69\u0026#39;), (\u0026#39;515200\u0026#39;, \u0026#39;3.32\u0026#39;), (\u0026#39;550001\u0026#39;, \u0026#39;3.06\u0026#39;), (\u0026#39;550008\u0026#39;, \u0026#39;3.05\u0026#39;), (\u0026#39;501081\u0026#39;, \u0026#39;3.05\u0026#39;), (\u0026#39;550009\u0026#39;, \u0026#39;2.99\u0026#39;), (\u0026#39;512220\u0026#39;, \u0026#39;2.95\u0026#39;), (\u0026#39;501076\u0026#39;, \u0026#39;2.26\u0026#39;), (\u0026#39;519013\u0026#39;, \u0026#39;2.09\u0026#39;), (\u0026#39;515880\u0026#39;, \u0026#39;10.75\u0026#39;), (\u0026#39;510080\u0026#39;, \u0026#39;1.60\u0026#39;), (\u0026#39;590007\u0026#39;, \u0026#39;0.99\u0026#39;), (\u0026#39;519676\u0026#39;, \u0026#39;0.71\u0026#39;)] 可以看到所有基金中持有中兴通讯最多份额的基金是515050，该基金持仓里中兴通讯占基金的比例为9.9%，意味着中兴通讯每涨停一天对基金会有0.99%的贡献。\n当然，这个办法有很多的局限性，比如基金持有的股票多数是优质股，这种机会比较难碰到，而且指数型基金往往持仓非常分散，也不适用这种办法。如果基金中其他股票下跌也会造成基金下跌。\n515050 5GETF这种主题基金比较适合这种个股利好涨停的，遇到针对整个行业的利好消息，这种主题型的ETF往往同时持有多只股票出现大幅上涨，2月24日当天，515050 这只基金除了中兴通讯涨停外，信维通信和沪电股份也出现了涨停，这三只股票基金持仓占比高达17.18%，如果之后出现了连续涨停的走势，对基金影响将非常明显。\n除了515050 5GETF还有其他几个比较适合的，比如159995 芯片ETF，515700 新能车，512760 半导体50等，可以都关注着，没准哪天掉下来个利好呢。\n","date":"2020-03-01T01:27:00Z","permalink":"https://eryk-github-io.pages.dev/2020/03/01/%E8%82%A1%E7%A5%A8%E9%87%8D%E5%A4%A7%E5%88%A9%E5%A5%BD%E5%BC%80%E7%9B%98%E5%B0%81%E6%B6%A8%E5%81%9C%E4%B9%B0%E4%B8%8D%E5%88%B0%E8%AF%95%E8%AF%95%E8%BF%99%E4%B8%AA%E5%8A%9E%E6%B3%95/","title":"股票重大利好开盘封涨停买不到？试试这个办法"},{"content":"今天我们通过一个例子来介绍python爬取数据的一般步骤，用到的工具包括python的经典模块requests和BeautifulSoup，另外结合刚学习的任务流工具TaskFlow来完成代码开发。\n我们先来看一下要爬取的数据，网址是http://data.10jqka.com.cn/funds/gnzjl/，通过chrome的开发者工具分析我们可以比较容易找到后台数据加载网址为\nhttp://data.10jqka.com.cn/funds/gnzjl/field/tradezdf/order/desc/page/{page_num}/ajax/1/free/1/\n其中page_num的位置为要查询第几页的数据，在网页上看到概念一共有6页数据，所以page_num取值为1-6\n这里有个小技巧，可以先点击图片左上角的清空按钮，把已经加载的网址先清理掉，然后在原始网页上点第二页，就能看到图片左下角新加载的网址，点开右边“Preview” 看到资金流数据相关的内容，就能确定这个网址是用来加载数据的。\n在chrome浏览器中输入 http://data.10jqka.com.cn/funds/gnzjl/field/tradezdf/order/desc/page/1/ajax/1/free/1/，并打开chrome开发者工具，在网页源码中找到数据所在table标签为\n1 2 3 \u0026lt;table class=\u0026#34;m-table J-ajax-table\u0026#34;\u0026gt; ... \u0026lt;/table\u0026gt; 抓取数据的完整源码如下\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 import time import requests from bs4 import BeautifulSoup from taskflow import engines from taskflow.patterns import linear_flow from taskflow.task import Task REQUEST_HEADER = { \u0026#39;User-Agent\u0026#39;: \u0026#39;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36\u0026#39;} class MoneyFlowDownload(Task): \u0026#34;\u0026#34;\u0026#34; 下载资金流数据 数据源地址：http://data.10jqka.com.cn/funds/gnzjl/ \u0026#34;\u0026#34;\u0026#34; BASE_URl = { \u0026#34;concept\u0026#34;: \u0026#39;http://data.10jqka.com.cn/funds/gnzjl/field/tradezdf/order/desc/page/%s/ajax/1/free/1/\u0026#39;, } def execute(self, bizdate, *args, **kwargs): for name, base_url in self.BASE_URl.items(): # 爬取数据的存储路径 dt_path = \u0026#39;/data/%s_%s.csv\u0026#39; % (bizdate, name) with open(dt_path, \u0026#34;a+\u0026#34;) as f: # 记录数据文件的当前位置 pos = f.tell() f.seek(0) lines = f.readlines() # 读取文件中的全部数据并将第一列存储下来作为去重依据，防止爬虫意外中断后重启程序时，重复写入相同 crawled_list = list(map(lambda line: line.split(\u0026#34;,\u0026#34;)[0], lines)) f.seek(pos) # 循环500次，从第一页开始爬取数据，当页面没有数据时终端退出循环 for i in range(1, 500): print(\u0026#34;start crawl %s, %s\u0026#34; % (name, base_url % i)) web_source = requests.get(base_url % i, headers=REQUEST_HEADER) soup = BeautifulSoup(web_source.content.decode(\u0026#34;gbk\u0026#34;), \u0026#39;lxml\u0026#39;) table = soup.select(\u0026#39;.J-ajax-table\u0026#39;)[0] tbody = table.select(\u0026#39;tbody tr\u0026#39;) # 当tbody为空时，则说明当前页已经没有数据了，此时终止循环 if len(tbody) == 0: break for tr in tbody: fields = tr.select(\u0026#39;td\u0026#39;) # 将每行记录第一列去掉，第一列为序号，没有存储必要 record = [field.text.strip() for field in fields[1:]] # 如果记录还没有写入文件中，则执行写入操作，否则跳过这行写入 if record[0] not in crawled_list: f.writelines([\u0026#39;,\u0026#39;.join(record) + \u0026#39;\\n\u0026#39;]) # 同花顺网站有反爬虫的机制，爬取速度过快很可能被封 time.sleep(1) if __name__ == \u0026#39;__main__\u0026#39;: bizdate = \u0026#39;20200214\u0026#39; tasks = [ MoneyFlowDownload(\u0026#39;moneyflow data download\u0026#39;) ] flow = linear_flow.Flow(\u0026#39;ths data download\u0026#39;).add(*tasks) e = engines.load(flow, store={\u0026#39;bizdate\u0026#39;: bizdate}) e.run() 执行程序后，在dt_path位置已经存储了概念的资金流数据，文件名为20200214_concept.csv，内容大致如下：\n1 2 3 钛白粉,1008.88,6.29%,7.68,6.21,1.47,7,金浦钛业,10.04%,2.96 磷化工,916.833,2.42%,37.53,34.78,2.75,28,六国化工,9.97%,4.08 光刻胶,1435.68,2.40%,43.51,44.31,-0.80,20,晶瑞股份,10.01%,42.99 此时就完成了同花顺概念分类的资金流数据的爬取，之后可以每天定时启动任务抓取数据进行分析。\n","date":"2020-02-16T01:14:00Z","permalink":"https://eryk-github-io.pages.dev/2020/02/16/%E4%BD%BF%E7%94%A8python%E6%8A%93%E5%8F%96%E5%90%8C%E8%8A%B1%E9%A1%BA%E8%B5%84%E9%87%91%E6%B5%81%E6%95%B0%E6%8D%AE/","title":"使用Python抓取同花顺资金流数据"},{"content":"TaskFlow 是一个以高度可用，易于理解和声明试方式来执行[作业，任务，流程]的库，可与OpenStack和其他项目一起使用。\n基本概念 taskflow库在oslo项目中是一个实现比较复杂的项目，要弄清楚其实现原理，首先需要对其中的相关概念有所了解。所以，本文首先总结了taskflow中常用的一些基本概念，这些概念主要包括如下几个：\nAtom Atom类是taskflow的最小单位，taskflow中其他类，包括Task等都需要继承这个类。一个Atom对象是一个命名对象，通过操作输入数据以执行一些促进整个流程发展的动作，或者产生一个处理结果等。它是一个抽象类，提供了两个抽象方法：execute()用于执行一个动作，revert()用于根据execute()执行结果和失败信息还原到任务执行之前的状态；除此之外，还分别为这两个方法提供了pre_execute()/post_execute()、pre_revert()/post_revert()方法用于定义在执行execute或revert操作前后执行的操作。\nTask Task类是一个拥有执行和回滚操作的最小工作单元，表示一个任务流中的某一个任务。它是一个继承自Atom类的表示一个任务的父类，开发者可以执行定义一个继承自Task类的任务类，并重写execute()和revert()方法分别表示执行和回滚的操作。\nTask的两种类型: Task: 对于继承和创建自己的子类很有用。 FunctorTask: 对于将现有function包装到任务对象中很有用，但是不能应用在engine中 Retry Retry类也是一个继承自Atom的抽象类，它主要定义了当有错误发生时，如何进行重试操作。其也包含也不同的类型，将会在接下来的部分进行详细介绍。继承重试的子类必须提供on_failure()函数来对故障进行处理。\n为避免重复创建常见的重试模式，提供了以下常见的重试子类： AlwaysRevert: 始终还原subflow.\nAlwaysRevertAll: 始终还原整个flow\nTimes: 对subflow重试指定次数\nForEach: 允许在每次发生故障时为subflow提供不同的值（使其有可能通过更改subflow输入来解决故障）\nParameterizedForEach: 和ForEach类似，但是从存储中获取值.\n关于重试的策略，taskflow通过一个枚举类型的Decision定义了三种策略：\nREVERT：仅回滚失败Flow对象周围或关联的子流Flow对象。该策略在回滚子流Flow对象之前，会首先咨询其父Atom对象以确定父Atom对象是否使用不同的重试策略。该策略允许安全的嵌套具有不同重试策略的Flow对象。如果父Atom对象中没有定义重试策略，则默认只回滚关联子流Flow对象中的Atom对象。当然，你可以通过defer_revert参数改变默认行为，当其设置为True，表示REVERT策略将继承父Atom的策略，如果父Atom对象没有重试策略，则它也将被回滚。 REVERT_ALL：不管失败Flow对象的父Atom对象的策略如何，都将回滚整个流程。 RETRY：重试该失败的Flow/Task对象。 Flow Flow类是一个用来关联所有相关Task类，并规定这些Task类的执行和回滚顺序的抽象类。而oslo中为Flow提供了三种实现方式：graph_flow表示图流，linear_flow表示线性流，unordered_flow表示无序流。关于这三种类型的流实现会在之后进行详细分析。\nlinear_flow：线性流，该类型的Flow对象将按照Task/Flow加入的顺序来依次执行，按照加入的倒序依次回滚。 graph_flow：图流，该类型的Flow对象会按照给加入的Task/Flow显示指定的依赖关系或通过其间的provides/requires属性隐含的依赖关系执行和回滚。 unordered_flow：无序流，该类型的Flow对象所加入的Task/Flow会按照任意顺序执行或回滚。 要弄清楚这三种类型的Flow对象，首先需要了解oslo定义的Flow基类的构成。在oslo定义的Flow基类中，主要包含以下几个重要的属性和方法：\nname：表示初始化Flow对象时，为其指定的名称，并不能唯一表示一个Flow对象。 retry：表示与该Flow对象关联的重试控制器。 provides：表示该Flow对象提供的一组符号名称。 requires：表示该Flow对象所需要的一组\u0026quot;unsatisfied\u0026quot;符号名称。 add(*items)：该方法用于为该Flow对象添加一个或一组Task/Flow对象。 iter_links()：迭代Flow对象的子节点之间的依赖关系链接。例如在迭代一个三元组(A, B, meta)时，就是迭代一个从子节点A（一个Atom对象或一个Subflow）指向子节点B（一个Atom对象或一个Subflow）的链接；换句话说，也就代表了子流B依赖于子流A，或者子流B需要子流A；而meta代表了这个依赖关系链接的元数据，是一个字典。 iter_nodes()：迭代Flow对象中的所有节点。例如在迭代一个二元组（A, meta）时，A（一个Atom对象或一个Subflow）是当前Flow对象的子流或子任务；meta同样代表了这个链接的元数据，是一个字典。 Engine Engine类是一个表示真正运行Atom对象的抽象类，它的实现类主要用于载入（load）一个Flow对象，然后驱动这个Flow对象的Task对象开始运行。Engine的实现也有多种不同的形式，这也会在接下来的部分进行详细介绍。\ntaskflow在具体实现Task/Flow管理时，首先定义了一个Engine抽象类，所有实现都需要继承这个抽象类。这个抽象类定义了如下重要属性和方法：\nnotifier：一个通知对象，它会分发与Engine对象中包含的Flow对象相关的事件通知。 atom_notifier：一个通知对象，它会分发与Engine对象中包含的Atom对象相关的事件通知。 options：相关数据结构传递给Engine对象的选项。 storage：Engine对象的存储单元。 statistics：Engine对象收集的运行时统计数据字典。当Engine没有运行时，这个值为空；在Engine正在运行时或已经运行之前，它可能会存储一些对正在运行或运行完成时有用的或包含信息的键值对。 compile()：该方法可以将Engine对象中包含的Flow对象编译成Engine对象内部表示形式。这个内部表示形式就是Engine对象实际用于运行的流的形式。 reset()：将Engine对象重置为PENDING状态。如果一个Flow以FAILURE、SUCCESS、REVERTED状态结束运行（即调用Engine对象的run()方法之后），或由于某种状态使得其处于某种中间状态，此时可以调用reset()方法进行重置，然后进行重试操作。 prepare()：在Engine对象编译完所有包含的Flow对象之后，且在Flow运行之前执行该方法，为流程的执行进行一些准备操作。 validate()：在Engine对象编译完所有包含的Flow对象之后，且在Flow运行之前执行该方法，为流程的执行进行一些验证操作。 run()：运行Engine对象中的Flow流程。 suspend()：该方法尝试暂停Engine对象。如果一个Engine对象正在执行某个Atom对象，则执行该方法会将这个Atom对象之后的所有正要运行的工作都暂停，并将这个Engine对象的状态变为暂停状态，以便之后进行恢复操作。 taskflow在具体实现Engine时，都需要给上述属性和方法重新赋值或进行覆写操作，以实现一个完整的管理流程Flow/Task对象的Engine类。在taskflow中，目前实现了三种策略的Engine类，而在这三种策略中，有两种是面向行为的action_egine类：SerialActionEngine、ParallelActionEngine；另一种是面向多进程的worker_base类：WorkerBaseActionEngine。这三种类型的Engine类的异同点如下所示：\nSerialActionEngine：这是一个以串行方式运行任务的Engine类，也就是说所有的任务都会在调用engine.run()方法的线程中顺序执行。 ParallelActionEngine：这是一个以并行方式运行任务的Engine类，即可以在多个线程中运行Engine对象中的任务。在这种策略中，taskflow定义了对应的多个ParallelThreadTaskExecutor创建运行任务的线程 WorkerBaseActionEngine：这是一个可以将任务调度到不同worker（即进程）中执行的Engine类。 ","date":"2020-02-08T23:13:00Z","permalink":"https://eryk-github-io.pages.dev/2020/02/08/openstack%E5%85%AC%E5%85%B1%E7%BB%84%E4%BB%B6taskflow%E4%BB%8B%E7%BB%8D/","title":"OpenStack公共组件TaskFlow介绍"},{"content":"第一章 系统的建立 1. 鉴定可交易的市场 流动性 流动性的最佳度量是交易量和未平仓合约数，观察一段时间的平均值优于观察单日 历史波动性 历史上趋势变化范围宽的市场优于平静的趋势变化范围窄的市场 准确的基本面和技术面数据 避免新市场 2. 鉴别走势 两条移动平均线，例如: 3和12，9和18，观察不到水平状态 3 \u0026gt; 12，上升趋势 3 \u0026lt; 12，下降趋势 三条移动平均线，例如: 4、9和18 4 \u0026gt; 9 \u0026gt; 18, 上升趋势 4 \u0026lt; 9 \u0026lt; 18, 下降趋势 其他，水平状态 移动平均线和其他技术指标组合 当指标发出的信号不一致时，认为市场无趋势或呈横向趋势 简单化 不建议运用翻转策略，因为这不能鉴定横向趋势的市场，并且总是存在于从多头到空头或者空头到多头的市场。这些反转系统总是倾向于在横向趋势的市场中出现锯齿状波动，毫无成功的可能，除非市场趋势持续如此。\n3. 市场择时 依赖单一的”神奇指标“不现实，要设计一个灵活的动态系统，在真实的不断变化的市场条件也能管用。\n市场的三种走势 长期走势：数周或数月 中期走势：最近几天 短期价格变化：前一天和当天 短期信号最先出现，其次是中期信号，最后是长期信号，当我们鉴别出了长期走势时，第一个中期和短期信号已经出现过了，因子，我们要利用会在长期走势中反复出现的中期和短期信号。\n耐心 等到市场时机成熟时进入，增加了每笔交易的利润，减少了必要的资本，减少了交易数量，大大提高了净利润额\n4. 建立止损 止损过近或过远 近止损，损失小、风险低、过早离场 远止损，胜率高、单笔损失大、风险高 理想的止损 建立可接受的止损程序可以通过将止损设立在随机价格波动范围外一点点的位置。\n一种可行的办法是算出价格移动平均线的标准差,在偏离移动平均线的最高点处建立止损。(布林带) 把每日价格变化的平均值作为建立止损的最小距离,这样可以避免大部分会产生小型的锯齿状波动的价格波动。 例如：建立5或10日移动平均线，将原始止损点设置于移动平均线之间的区间相等的最小距离处。 止损方法要保持一致 5. 退市择时 跟踪止损法 相对强弱指标（RSI） 退市策略绩效可使用随机入市的方法验证效果\n6. 再入市择时 退市策略是更为重要，所以使用可能的最佳的退市策略，然后调节退市后会被触发的再入市指标的敏感度。\n7. 监控系统 每周期交易频率，比如每月1.5笔 盈利交易笔数与亏损交易笔数的百分比 最糟糕的周期中盈利笔数 最佳周期中盈利笔数 最长连续亏损 连续盈利交易 每笔盈利交易的平均收益 平均亏损交易额 最大回吐 最大回吐恢复时长 第二章 技术研究 方向性运动指标DMI和平均方向性运动指数ADX * 下降的ADX预示着市场不呈现任何趋势，应该采取逆势策略，而不是顺势策略。 * ADX滞后性 布林带、包络线和通道 通道突破作为确认方法\n商品通道指数CCI 背离 趋势性市场和非趋势性市场 非趋势性市场偏离交易朝两个方向都可以进行，而在趋势性市场逆势的偏离信号一般应该被忽略（视图抓住大的顶部和底部除外） 连续偏离 连续三次偏离 相关市场偏离 动力指标和变化率 动力指标精确测量了市场的运转速度,从某种程度上说,测量了一种趋势完好存在的程度。\n计算过程：用当日的收盘价减去n天前的收盘价,结果是一个位于零点或零线附近的正数或负数。\n公式：\nM = Pt - Pt-n\nM是动力指标,Pt是当日的收盘价,Pt-n是Pt时间段(通常是天)前的收盘价。\n变化率的公式是:\nROC=100(Pt/Pt-n)\n动力线和零线交叉次数随着动力线指标计算中使用的时间周期的不同而变化。时间周期短，动力线与零线交叉得约频繁，指标发出信号的速度越快。\n动力线最有效的用途之一是界定长期趋势。25周期的动力周线图是个非常可靠的长期走势指标。当动力线迅速离开零线时，顺势交易会带来丰厚的回报。\n其他指标的动力指标量化倾斜度\n移动平均线 简单移动平均线\n加权移动平均线\n指数移动平均线\n三条移动平均线: 4-9-18均线法\n四条移动平均线\n移位后的移动平均线\n发现过滤器\nMACD 抛物线指标SAR 最大的价值是用来建立止损点\n相对强弱指标RSI RSI \u0026gt; 75 or RSI \u0026lt; 25，推迟入市\n慢速随机指标KDJ 随机指标最不适合用于只有持续的微小变动的趋势性市场\n左右交点 波动性 平均真实区间（ATR） 突破或价格峰值超出近期区间或平均真实区间是十分重要的信号,应作为入市点。 第三章 系统测试 避免最优化\n从统计学的角度而言,少于30笔交易,产生的结果就不可靠。交易笔数大于30的程度越多\n积累的前进测试，滚动前进最优化处理\n衡量绩效 夏普比率(Sharpe Ratio) 其定义为年度化的收益(一种盈利性度量形式)与无风险收益率的差除以年度化的收益标准差(一种波动度量形式)。\n英镑比率(Sterling Ratio) 英镑比率=年平均收益比率/[(1×3年平均最大亏损) + 10]\n卡尔玛比率(Calmar Ratio) 几何平均数 几何平均数衡量的是你的交易系统的增长因子。几何平均数越高,你的系统再投资时创造高收益的潜力就越大。\n净盈利 测试样例中的交易数 总交易数必须大于30，这是为了确保统计上的重要结果的可靠性。\n最大盈利及最大的亏损交易 倘若最大的盈利交易不合理地歪曲了净盈利额，它就很重要。许多保守的系统测试员会剔除每种商品中的最大盈利交易,然后再次评价结果。\n最大的连续盈利交易和亏损交易 峰到谷式的亏损 计算最大净资产额最为准确的方法是取日总净资产额的最高值与随后的日总净资产额的最低值之差值。\n盈利交易百分比 大部分成功的顺势交易商拥有35%到45%的盈利交易。要达到55%以上是很困难的\n平均盈利与平均亏损比率 总收益的最大亏损 波动性和破产的概率 测试入市、退市及止损方法 如果你的风险控制由两种类型的止损方法组成,一个是简单的定额止损法,另一个是将止损位设置为近期高价或低价，如果你知道每种止损价位被触及的频率,这对设计和测试过程会有帮助的。\n测试入市方法 在整体方案中,退市方法确实要比入市方法重要,毕竟,交易的结果最终由退市决定,当入市做对了后，找到良好的退市方法就要容易很多。\n有效测试一个交易系统的任何单个的要素的最佳方法就是尽量将它分离开来。建立你自己的交易系统，然后删去通常的退出方法。用一种可以在进入每笔交易特定天数后自动退出市场的方法取代原先的退市方法。\n测试退市策略 选择一种结果合理的入市方法作为反转系统，然后用相同的数据和入市方法对每种退市策略一一进行测试。\n从理论上讲，比入市方法更敏感的退市方法应该捕捉到每个市场变动的更多的信息。以下是对我们测试的退市策略的一个描述。\n跟踪止损 初始风险是指进入市场点与控制风险的止损点之间的差距。净资产额风险是指开立的头寸的市场价格与你的退市策略暗示的价格之间的差值。\n测试止损策略 初始风险止损 初始风险止损可定义为一种以某种方式限制一笔交易从入市点就可能累积的亏损的止损。当一笔交易对我们不利时，初始风险止损通常先于任何其它类型的退市策略被触发。它是你最基本的“止损”指令。\n定额止损 支撑/阻力 无利退出, 如果交易在一定天数后无利可获则退出 保本止损 保本止损被定义为一旦交易达到一定的利润额，在入市点建立的止损。这种止损的目的明显是要防止合理的利润变为亏损。\n跟踪止损 跟踪止损是指达到一些合乎逻辑的价格点后，不断计算得出的止损价。跟踪止损可以用作初始风险止损或取利退市策略，或者兼任两者功能。\n从收盘价开始跟踪的定额止损 这种止损是从交易方向的最高收盘价或最低收盘价开始计算止损点。 从高价或低价开始跟踪的定额止损 一旦达到某一盈利高度，就应该跟踪止损保护一定数目的收益。交易的损失将会被限制在交易所达到的高价和低价以及跟踪止损的高价和低价的差额范围内。这种止损可即刻跟踪，并且可以用作初始风险止损，也可以用作跟踪止损。 创建一个简单的交易系统 交易系统的目标 年回报率20% ~ 30%，盈利交易百分比大于40%，平均盈利与平均亏损的比率至少为2:1\n风险控制 初始风险 即入市点与保护性止损点之间的差距 资产风险 即投入市场的净资产额与跟踪止损价位之间的差额。这两类风险还可以进一步分为单笔交易中的初始风险和资产风险，以及跨投资组合同时交易的初始风险和资产风险。 第四章 日交易 交易成本 手续费和点差\n市场选择 当日high和low价差的绝对值高，或者更高的时间比率。持续的高波动性是日内交易市场或标的选择的重要指标。\n考虑最小变动价位的大小 流动性及最小价差的大小也是选择日交易市场时应该考虑的因素\n日交易商不断地面临着从相对小的价格变化幅度中获取最大利润的问题。这种情况自然使得交易商采取回调时买进、反弹时卖出的策略,而不是试图去顺应走势。大部分的顺势策略对于日交易而言往往太慢。逆势策略提供了从一个小的价格变化幅度中获取最大利润的可能性。然而，逆势策略往往不如顺势策略那么可靠，因为快速地识别出价格的转轨点比简单的顺势交易要难得多。\n成功的日交易商试图在上升趋势阶段中的回调时买进，在下降趋势阶段在反弹时卖出。想持续赚钱的日交易商必须善于顺应趋势，又要善于发现短期的转折点。许多交易商亏钱是因为他们两者都不擅长。看过一些可能的日交易策略的例子后，请记住两个步骤：首先找出中期走势，然后找出短期转折点。要想获得盈利的日交易，两步都要进行得快而准。\n我的微信公众号：pyquant\n","date":"2019-06-19T09:42:00Z","permalink":"https://eryk-github-io.pages.dev/2019/06/19/%E8%AF%BB%E6%9C%9F%E8%B4%A7%E5%B8%82%E5%9C%BA%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%88%86%E6%9E%90%E6%8C%87%E5%8D%97%E7%AC%94%E8%AE%B0/","title":"读《期货市场计算机分析指南》笔记"},{"content":"这篇文章原文出自kaggle，我大致翻译翻一下，文中给出了reduce_mem_usage方法可以用来自动缩减dataframe占用空间\n这篇notebook展示了通过使用更合理的数据类型来减少dataframe的内存使用量\n方法如下：\n迭代每一个column 检查column是否为数字型 检查column是否可以用integer表示 找出column下的最大值和最小值 选择适用于数据范围的最合适的数据类型 通过以上步骤处理后将一份测试数据从1.3GB减少到466MB\n源码如下:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 import numpy as np # linear algebra import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv) def reduce_mem_usage(props): start_mem_usg = props.memory_usage().sum() / 1024**2 print(\u0026#34;Memory usage of properties dataframe is :\u0026#34;,start_mem_usg,\u0026#34; MB\u0026#34;) NAlist = [] # Keeps track of columns that have missing values filled in. for col in props.columns: if props[col].dtype != object: # Exclude strings # Print current column type print(\u0026#34;******************************\u0026#34;) print(\u0026#34;Column: \u0026#34;,col) print(\u0026#34;dtype before: \u0026#34;,props[col].dtype) # make variables for Int, max and min IsInt = False mx = props[col].max() mn = props[col].min() # Integer does not support NA, therefore, NA needs to be filled if not np.isfinite(props[col]).all(): NAlist.append(col) props[col].fillna(mn-1,inplace=True) # test if column can be converted to an integer asint = props[col].fillna(0).astype(np.int64) result = (props[col] - asint) result = result.sum() if result \u0026gt; -0.01 and result \u0026lt; 0.01: IsInt = True # Make Integer/unsigned Integer datatypes if IsInt: if mn \u0026gt;= 0: if mx \u0026lt; 255: props[col] = props[col].astype(np.uint8) elif mx \u0026lt; 65535: props[col] = props[col].astype(np.uint16) elif mx \u0026lt; 4294967295: props[col] = props[col].astype(np.uint32) else: props[col] = props[col].astype(np.uint64) else: if mn \u0026gt; np.iinfo(np.int8).min and mx \u0026lt; np.iinfo(np.int8).max: props[col] = props[col].astype(np.int8) elif mn \u0026gt; np.iinfo(np.int16).min and mx \u0026lt; np.iinfo(np.int16).max: props[col] = props[col].astype(np.int16) elif mn \u0026gt; np.iinfo(np.int32).min and mx \u0026lt; np.iinfo(np.int32).max: props[col] = props[col].astype(np.int32) elif mn \u0026gt; np.iinfo(np.int64).min and mx \u0026lt; np.iinfo(np.int64).max: props[col] = props[col].astype(np.int64) # Make float datatypes 32 bit else: props[col] = props[col].astype(np.float32) # Print new column type print(\u0026#34;dtype after: \u0026#34;,props[col].dtype) print(\u0026#34;******************************\u0026#34;) # Print final result print(\u0026#34;___MEMORY USAGE AFTER COMPLETION:___\u0026#34;) mem_usg = props.memory_usage().sum() / 1024**2 print(\u0026#34;Memory usage is: \u0026#34;,mem_usg,\u0026#34; MB\u0026#34;) print(\u0026#34;This is \u0026#34;,100*mem_usg/start_mem_usg,\u0026#34;% of the initial size\u0026#34;) return props, NAlist 原文链接：\nhttps://www.kaggle.com/arjanso/reducing-dataframe-memory-size-by-65\n我的微信公众号：pyquant\n","date":"2019-06-05T10:48:00Z","permalink":"https://eryk-github-io.pages.dev/2019/06/05/%E5%B0%86dataframe%E5%86%85%E5%AD%98%E5%A4%A7%E5%B0%8F%E5%87%8F%E5%B0%91%E7%BA%A665/","title":"将DataFrame内存大小减少约65％"},{"content":"读写API HDFStore支持使用read_hdf进行读取和使用to_hdf进行写入的top-level API，类似于read_csv和to_csv的工作方式。\n默认情况下，HDFStore不会丢弃全部为na的行。可以通过设置dropna = True来更改此行为。\n1 2 3 4 5 import pandas as pd import h5py df_tl = pd.DataFrame({\u0026#39;A\u0026#39;: list(range(5)), \u0026#39;B\u0026#39;: list(range(5))}) df_tl.to_hdf(\u0026#39;store_tl.h5\u0026#39;, \u0026#39;table\u0026#39;, append=True) pd.read_hdf(\u0026#39;store_tl.h5\u0026#39;, \u0026#39;table\u0026#39;, where=[\u0026#39;index\u0026gt;2\u0026#39;]) HDF数据类型 Fixed Format 一次写入，重复读取，不可追加 不可以使用where查询，比如每次获取指定key的全部内容 不支持dataframe有非唯一的column 相比于table格式更快的读写速度 使用put或者to_hdf时的默认类型，也可以通过format=\u0026lsquo;fixed\u0026rsquo;或format=\u0026lsquo;f\u0026rsquo;指定类型 Table Format 支持append操作 支持删除和查询类型操作 执行put或者to_hdf操作时通过设置format=\u0026lsquo;table\u0026rsquo;或format=\u0026rsquo;t\u0026rsquo;指定table格式 pd.set_option(\u0026lsquo;io.hdf.default_format\u0026rsquo;,\u0026rsquo;table\u0026rsquo;) 设置默认hdf format类型 在第一次append/put操作之后，您无法更改数据列（也不能转换索引）（当然，您只需读取数据并创建新表！）。\n警告HDFStore对于写入不是线程安全的。底层PyTables仅支持并发读取（通过线程或进程）。如果您需要同时进行读写，则需要在单个进程中在单个线程中序列化这些操作。否则你将破坏你的数据。\nTODO 验证append是否会按照index排序的例子\nHierarchical Keys key可以包含路径，例如\u0026rsquo;/food/apple\u0026rsquo;, 存储时会自动创建sub-stores(在pytables中是groups)，可以省略路径开头的\u0026rsquo;/\u0026rsquo;，\u0026rsquo;/food/apple\u0026rsquo;和\u0026rsquo;food/apple\u0026rsquo;表示相同的key。\n注意：删除操作会删除子路径下的所有内容，请小心使用\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 df = pd.DataFrame({\u0026#39;A\u0026#39;: list(range(2)), \u0026#39;B\u0026#39;: list(range(2))}) store = pd.HDFStore(\u0026#39;hk_test.h5\u0026#39;) store.append(\u0026#39;/food/apple\u0026#39;, df) store.append(\u0026#39;food/orange\u0026#39;, df) store.append(\u0026#39;df\u0026#39;,df) print(store.keys()) for (path, subgroups, subkeys) in store.walk(): for subgroup in subgroups: print(\u0026#39;GROUP: {}/{}\u0026#39;.format(path, subgroup)) for subkey in subkeys: key = \u0026#39;/\u0026#39;.join([path, subkey]) print(\u0026#39;KEY: {}\u0026#39;.format(key)) print(store.get(key)) print(store[\u0026#39;food/orange\u0026#39;]) 查询 select和delete操作可以通过查询语句对数据子集进行操作，好处是可以在非常大的数据集上只检索一小部分数据。\n查询表达式:\n支持使用index和columns查询dataframe 支持使用major_axis、minor_axis和items查询Panel 如果指定data_columns，则它将被作为附加索引器 有效的比较运算符是：\n=, ==, !=, \u0026gt;, \u0026gt;=, \u0026lt;, \u0026lt;=\n有效的布尔表达式包括：\n| : 或操作 \u0026amp; : 与操作 ( 和 ) : 分组 例子：\n\u0026lsquo;index \u0026gt;= date\u0026rsquo; \u0026ldquo;columns = [\u0026lsquo;A\u0026rsquo;, \u0026lsquo;D\u0026rsquo;]\u0026rdquo; \u0026ldquo;columns in [\u0026lsquo;A\u0026rsquo;, \u0026lsquo;D\u0026rsquo;]\u0026rdquo; \u0026lsquo;columns = A\u0026rsquo; \u0026lsquo;columns == A\u0026rsquo; \u0026ldquo;~(columns = [\u0026lsquo;A\u0026rsquo;, \u0026lsquo;B\u0026rsquo;])\u0026rdquo; \u0026lsquo;index \u0026gt; df.index[3] \u0026amp; string = \u0026ldquo;bar\u0026rdquo;\u0026rsquo; \u0026lsquo;(index \u0026gt; df.index[3] \u0026amp; index \u0026lt;= df.index[6]) | string = \u0026ldquo;bar\u0026rdquo;\u0026rsquo; \u0026ldquo;ts \u0026gt;= Timestamp(\u0026lsquo;2012-02-01\u0026rsquo;)\u0026rdquo; \u0026ldquo;major_axis\u0026gt;=20130101\u0026rdquo; 不建议通过将字符串插入查询表达式来将字符串传递给查询。只需将感兴趣的字符串分配给变量，并在表达式中使用该变量。 例如：\n1 2 3 4 5 string = \u0026#34;HolyMoly\u0026#39;\u0026#34; store.select(\u0026#39;df\u0026#39;, \u0026#39;index == string\u0026#39;) store.select(\u0026#39;dfq\u0026#39;, \u0026#34;index\u0026gt;pd.Timestamp(\u0026#39;20130104\u0026#39;) \u0026amp; columns=[\u0026#39;A\u0026#39;, \u0026#39;B\u0026#39;]\u0026#34;) store.select(\u0026#39;dfq\u0026#39;, where=\u0026#34;A\u0026gt;0 or C\u0026gt;0\u0026#34;) store.select(\u0026#39;df\u0026#39;, \u0026#34;columns=[\u0026#39;A\u0026#39;, \u0026#39;B\u0026#39;]\u0026#34;) 删除 1 store.remove(\u0026#39;wp\u0026#39;, \u0026#39;major_axis \u0026gt; 20000102\u0026#39;) 警告: 请注意HDF5不会自动回收h5文件中的空格。因此，反复删除（或删除节点）并再次添加，将趋于增加文件大小。\n压缩 complevel指定压缩强度，complevel = 0和complevel = None禁用压缩，0 \u0026lt;complevel \u0026lt;10启用压缩。 complib 指定压缩库，默认使用zlib zlib：默认的压缩库。压缩方面的经典之作可以实现良好的压缩率，但速度有些慢。 lzo：快速压缩和减压。 bzip2：良好的压缩率。 blosc：快速压缩和解压缩。 blosc：blosclz这是blosc的默认压缩器 blosc：lz4：紧凑，非常流行和快速的压缩机。 blosc：lz4hc：LZ4的调整版本，以牺牲速度为代价产生更好的压缩比。 blosc：snappy：在许多地方使用的流行压缩器。 blosc：zlib：经典;比以前慢一些，但实现了更好的压缩比。 blosc：zstd：非常平衡的编解码器;它提供了上述其他压缩比，并且速度相当快。 1 2 3 store_compressed = pd.HDFStore(\u0026#39;store_compressed.h5\u0026#39;, complevel=9,complib=\u0026#39;blosc:blosclz\u0026#39;) store.append(\u0026#39;df\u0026#39;, df, complib=\u0026#39;zlib\u0026#39;, complevel=5) ptrepack 重新生成压缩文件，重写文件将回收已删除的空间，也可以改变complevel\n1 ptrepack --chunkshape=auto --propindexes --complevel=9 --complib=blosc in.h5 out.h5 性能 fixed stores 读写速度快于 tables 格式，但tables支持追加、删除和查询操作 可以设置chunksize=\u0026lt; int \u0026gt;来指定chunsize大小，这将会降低写入时的内存使用量 设置expectedrows 可以优化读写性能 Duplicate rows将会被写入tables，在select时会被过滤掉 我的微信公众号：pyquant\n","date":"2019-05-08T21:51:00Z","permalink":"https://eryk-github-io.pages.dev/2019/05/08/pandas-hdf5%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97%E7%BF%BB%E8%AF%91/","title":"Pandas hdf5使用指南翻译"},{"content":"我的微信公众号：pyquant\n大家好，这篇文章我将使用Pandas创建一个简单的均线交叉策略，以500ETF作为标的物进行回测\n移动平均线可能是技术指标里的\u0026quot;hello world\u0026quot;了，常用的均线有5、10、20、60、120日均线，在其他时间周期上应用移动平均线指标也是类似方式。\n移动平均线按时间周期长短分为：短期移动平均线，中期移动平均线，长期移动平均线；按计算方法分为：算术移动平均线，加权移动平均线，指数平滑移动平均线（EMA）\n下面正式开始编写策略代码，我们使用jupyer作为研究环境，首先先导入依赖模块\n1 2 3 4 5 import pandas as pd import numpy as np import tushare as ts %matplotlib inline 接下来使用tushare下载500ETF的历史数据，500ETF是从2013年开始上市交易的，这里将start参数设置为2013，这样可以获取500ETF的全部历史数据。\n1 2 3 4 etf500 = ts.get_k_data(\u0026#39;510500\u0026#39;,start=\u0026#39;2013\u0026#39;) etf500.set_index(pd.to_datetime(etf500[\u0026#39;date\u0026#39;]),inplace=True) del etf500[\u0026#39;date\u0026#39;] etf500.head() 输出结果如下，数据是从2013年3月15日开始的：\ndate open close high low volume code 2013-03-15 0.967 0.970 0.985 0.955 3259273.0 510500 2013-03-18 0.955 0.954 0.972 0.953 936962.0 510500 2013-03-19 0.956 0.960 0.960 0.941 1080499.0 510500 2013-03-20 0.960 0.985 0.986 0.958 501195.0 510500 2013-03-21 0.985 0.995 0.996 0.981 698243.0 510500 继续画出收盘价格曲线，对500ETF走势有个大概的了解。\n1 etf500[\u0026#39;close\u0026#39;].plot(grid=True, figsize=(8,5)) 接下来是双均线策略的实现，我们使用20日均线和60日均线作为短期和长期均线，下面先分别计算20日和60日均线序列\n1 2 3 etf500[\u0026#39;ma20\u0026#39;] = etf500[\u0026#39;close\u0026#39;].rolling(20).mean() etf500[\u0026#39;ma60\u0026#39;] = etf500[\u0026#39;close\u0026#39;].rolling(60).mean() etf500[[\u0026#39;close\u0026#39;,\u0026#39;ma20\u0026#39;,\u0026#39;ma60\u0026#39;]].plot(grid=True, figsize=(14,5)) 我们已经获取了两条移动平均线序列，接下来是根据均线来生成交易信号\n策略信号会有两种状态：\n买入信号，当20日均线向上穿过60日均线时持有多头仓位\n卖出信号，当20日均线向下穿过60日均线时平仓\n1 2 etf500[\u0026#39;Stance\u0026#39;] = np.where(etf500[\u0026#39;ma20\u0026#39;] - etf500[\u0026#39;ma60\u0026#39;] \u0026gt; 0, 1, 0) etf500[\u0026#39;Stance\u0026#39;].value_counts() 最后一行统计持仓和空仓的天数，输出结果如下：\n1 2 3 1 761 0 724 Name: Stance, dtype: int64 1 etf500[\u0026#39;Stance\u0026#39;].plot(ylim=[-0.1,1.1]) 下图显示持仓日期数据\n接下来，我们根据持仓数据来计算持仓的收益\n1 2 3 etf500[\u0026#39;Market Returns\u0026#39;] = np.log(etf500[\u0026#39;close\u0026#39;] / etf500[\u0026#39;close\u0026#39;].shift(1)) etf500[\u0026#39;Strategy\u0026#39;] = etf500[\u0026#39;Market Returns\u0026#39;] * etf500[\u0026#39;Stance\u0026#39;].shift(1) etf500[[\u0026#39;Market Returns\u0026#39;,\u0026#39;Strategy\u0026#39;]].cumsum().plot(grid=True,figsize=(8,5)) 以上图片展示了市场回报率与策略回报曲线，可以看到20和60日双均线策略并没有跑赢500ETF，不过我们也可以测试下其他均线组合，也许会有不错的效果。\n参考 https://www.pythonforfinance.net/2016/09/01/moving-average-crossover-trading-strategy-backtest-in-python/#more-15498\u003e\n","date":"2019-04-24T20:47:00Z","permalink":"https://eryk-github-io.pages.dev/2019/04/24/%E4%BD%BF%E7%94%A8pandas%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E5%9D%87%E7%BA%BF%E7%AD%96%E7%95%A5/","title":"使用Pandas开发一个均线策略"},{"content":"我的微信公众号：pyquant\n背景 开发股票行情推送的引擎时遇到一个问题，在9:30开盘后的一段时间内行情消息总是堆积，尤其是开头15-20分钟，堆积的数据量会越来越多，经过debug发现是内部消息传输使用Queue性能问题导致了消息延迟，在stackoverflow上找到一个帖子对Queue的性能进行了测试和解释说明，下面先来介绍下Multiprocessing下的Queue和Pipe\n介绍 当使用多个进程时，通常使用消息传递来进行进程之间的通信，为了不损耗性能也会尽量避免使用同步机制。对于消息传递：\n* Pipe适用于两个进程间的消息传递。 * Queue适用于多个进程间的消息传递，适用于多生产者和消费者的模式。 Pipe VS Queue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from multiprocessing import Process, Pipe import time def reader_proc(pipe): ## Read from the pipe; this will be spawned as a separate Process p_output, p_input = pipe p_input.close() # We are only reading while True: msg = p_output.recv() # Read from the output pipe and do nothing if msg == \u0026#39;DONE\u0026#39;: break def writer(count, p_input): for ii in range(0, count): p_input.send(ii) # Write \u0026#39;count\u0026#39; numbers into the input pipe p_input.send(\u0026#39;DONE\u0026#39;) if __name__ == \u0026#39;__main__\u0026#39;: for count in [10 ** 4, 10 ** 5, 10 ** 6]: # Pipes are unidirectional with two endpoints: p_input ------\u0026gt; p_output p_output, p_input = Pipe() # writer() writes to p_input from _this_ process reader_p = Process(target=reader_proc, args=((p_output, p_input),)) reader_p.daemon = True reader_p.start() # Launch the reader process p_output.close() # We no longer need this part of the Pipe() _start = time.time() writer(count, p_input) # Send a lot of stuff to reader_proc() p_input.close() reader_p.join() print(\u0026#34;Sending {0} numbers to Pipe() took {1} seconds\u0026#34;.format(count, (time.time() - _start))) Pipe输出结果 1 2 3 Sending 10000 numbers to Pipe() took 0.0744009017944336 seconds Sending 100000 numbers to Pipe() took 0.7794349193572998 seconds Sending 1000000 numbers to Pipe() took 7.425454139709473 seconds 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 from multiprocessing import Process, Queue import time import sys def reader_proc(queue): ## Read from the queue; this will be spawned as a separate Process while True: msg = queue.get() # Read from the queue and do nothing if (msg == \u0026#39;DONE\u0026#39;): break def writer(count, queue): ## Write to the queue for ii in range(0, count): queue.put(ii) # Write \u0026#39;count\u0026#39; numbers into the queue queue.put(\u0026#39;DONE\u0026#39;) if __name__ == \u0026#39;__main__\u0026#39;: pqueue = Queue() # writer() writes to pqueue from _this_ process for count in [10 ** 4, 10 ** 5, 10 ** 6]: ### reader_proc() reads from pqueue as a separate process reader_p = Process(target=reader_proc, args=((pqueue),)) reader_p.daemon = True reader_p.start() # Launch reader_proc() as a separate python process _start = time.time() writer(count, pqueue) # Send a lot of stuff to reader() reader_p.join() # Wait for the reader to finish print(\u0026#34;Sending {0} numbers to Queue() took {1} seconds\u0026#34;.format(count, (time.time() - _start))) Queue 输出结果 1 2 3 Sending 10000 numbers to Queue() took 0.2558887004852295 seconds Sending 100000 numbers to Queue() took 2.4320709705352783 seconds Sending 1000000 numbers to Queue() took 23.602338075637817 seconds 让我们把结果整理成表格方便对比查看:\n循环次数 Pipe Queue 10000 0.0744 0.2558 100000 0.7794 2.4320 1000000 7.4254 23.6023 通过对比测试可以发现，Pipe性能大约为Queue的3倍，所以在仅有两端通信的情况下应该优先使用Pipe。\n源码分析 通过阅读Queue的源码，我们可以发现，其实在Queue内部是用Lock来实现对Pipe的安全读写操作的。所以相比于Pipe会有额外的锁的开销。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 class Queue(object): def __init__(self, maxsize=0, *, ctx): if maxsize \u0026lt;= 0: # Can raise ImportError (see issues #3770 and #23400) from .synchronize import SEM_VALUE_MAX as maxsize self._maxsize = maxsize self._reader, self._writer = connection.Pipe(duplex=False) # 这里初始化了Pipe对象 self._rlock = ctx.Lock() self._opid = os.getpid() if sys.platform == \u0026#39;win32\u0026#39;: self._wlock = None else: self._wlock = ctx.Lock() self._sem = ctx.BoundedSemaphore(maxsize) # For use by concurrent.futures self._ignore_epipe = False self._after_fork() if sys.platform != \u0026#39;win32\u0026#39;: register_after_fork(self, Queue._after_fork) def put(self, obj, block=True, timeout=None): if self._closed: raise ValueError(f\u0026#34;Queue {self!r} is closed\u0026#34;) if not self._sem.acquire(block, timeout): raise Full with self._notempty: if self._thread is None: self._start_thread() self._buffer.append(obj) self._notempty.notify() def get(self, block=True, timeout=None): if self._closed: raise ValueError(f\u0026#34;Queue {self!r} is closed\u0026#34;) if block and timeout is None: with self._rlock: res = self._recv_bytes() self._sem.release() else: if block: deadline = time.monotonic() + timeout if not self._rlock.acquire(block, timeout): raise Empty try: if block: timeout = deadline - time.monotonic() if not self._poll(timeout): raise Empty elif not self._poll(): raise Empty res = self._recv_bytes() self._sem.release() finally: self._rlock.release() # unserialize the data after having released the lock return _ForkingPickler.loads(res) 参考 https://stackoverflow.com/questions/8463008/multiprocessing-pipe-vs-queue\n","date":"2019-04-22T10:47:00Z","permalink":"https://eryk-github-io.pages.dev/2019/04/22/multiprocessing-pipe%E5%92%8Cqueue%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/","title":"Multiprocessing Pipe和Queue性能测试"},{"content":"我的微信公众号：pyquant\n在写代码时经常会遇到对抛出异常的代码进行重试，常见于网页爬虫的代码中，使用计数器 + 循环的方式对抛出异常的代码进行捕获和重试。tenacity是使用Python装饰器模式对方法异常进行捕获，通过灵活的参数实现简单优雅的异常重试。\n特性： 简单灵活的装饰模式api 可以指定重试停止条件（比如：设置重试次数） 也可以指定等待条件（比如：使用指数避让间隔重试） 自定义触发重试的Exception 自定义重试预期的返回结果 基于协程的重试 安装方式: pip install tenacity\nAPI使用介绍 1. @retry 给需要重试的方法加上@retry修饰器之后，方法抛出异常就会被装饰器捕获到并进行重试，异常抛出时会不断重试直到方法成功返回\n1 2 3 4 @retry def never_give_up_never_surrender(): print(\u0026#34;Retry forever ignoring Exceptions, don\u0026#39;t wait between retries\u0026#34;) raise Exception 2. 带终止条件的retry 我们也可以给retry加一个参数设置重试n次后不再重试并抛出异常\n1 2 3 4 @retry(stop=stop_after_attempt(7)) def stop_after_7_attempts(): print(\u0026#34;Stopping after 7 attempts\u0026#34;) raise Exception 使用@stop_after_delay 可以指定重试间隔，比如如下的例子指定10秒后重试\n1 2 3 4 @retry(stop=stop_after_delay(10)) def stop_after_10_s(): print(\u0026#34;Stopping after 10 seconds\u0026#34;) raise Exception 可以使用 \u0026ldquo;|\u0026rdquo; 把多个条件组合起来\n1 2 3 4 @retry(stop=(stop_after_delay(10) | stop_after_attempt(5))) def stop_after_10_s_or_5_retries(): print(\u0026#34;Stopping after 10 seconds or 5 retries\u0026#34;) raise Exception 3. 在重试前等待 使用@wait_fixed 在重试前等待固定时间\n1 2 3 4 @retry(wait=wait_fixed(2)) def wait_2_s(): print(\u0026#34;Wait 2 second between retries\u0026#34;) raise Exception 随机等待1-2秒钟，这在爬虫爬网页时比较有用\n1 2 3 4 @retry(wait=wait_random(min=1, max=2)) def wait_random_1_to_2_s(): print(\u0026#34;Randomly wait 1 to 2 seconds between retries\u0026#34;) raise Exception 增加指数避让等待间\n1 2 3 4 5 6 7 8 9 @retry(wait=wait_exponential(multiplier=1, min=4, max=10)) def wait_exponential_1(): print(\u0026#34;Wait 2^x * 1 second between each retry starting with 4 seconds, then up to 10 seconds, then 10 seconds afterwards\u0026#34;) raise Exception @retry(wait=wait_fixed(3) + wait_random(0, 2)) def wait_fixed_jitter(): print(\u0026#34;Wait at least 3 seconds, and add up to 2 seconds of random delay\u0026#34;) raise Exception 看一个更复杂点的例子\n1 2 3 4 5 6 @retry(wait=wait_chain(*[wait_fixed(3) for i in range(3)] + [wait_fixed(7) for i in range(2)] + [wait_fixed(9)])) def wait_fixed_chained(): print(\u0026#34;Wait 3s for 3 attempts, 7s for the next 2 attempts and 9s for all attempts thereafter\u0026#34;) raise Exception 4. 带触发条件的retry语句 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @retry(retry=retry_if_exception_type(IOError)) def might_io_error(): print(\u0026#34;Retry forever with no wait if an IOError occurs, raise any other errors\u0026#34;) raise Exception def is_none_p(value): \u0026#34;\u0026#34;\u0026#34;Return True if value is None\u0026#34;\u0026#34;\u0026#34; return value is None @retry(retry=retry_if_result(is_none_p)) def might_return_none(): print(\u0026#34;Retry with no wait if return value is None\u0026#34;) @retry(retry=(retry_if_result(is_none_p) | retry_if_exception_type())) def might_return_none(): print(\u0026#34;Retry forever ignoring Exceptions with no wait if return value is None\u0026#34;) 5. 异常处理 虽然tenacity会帮我们处理异常，我们依然可以在重试失败后使用reraise来决定我们时候进行最后的尝试，使用reraise会把异常抛出交给我们的try except来处理\n1 2 3 4 5 6 7 8 9 @retry(reraise=True, stop=stop_after_attempt(3)) def raise_my_exception(): raise MyException(\u0026#34;Fail\u0026#34;) try: raise_my_exception() except MyException: # timed out retrying pass 6. 在retry前后增加log 1 2 3 4 5 6 7 8 9 10 11 12 13 14 logger = logging.getLogger(__name__) @retry(stop=stop_after_attempt(3), before=before_log(logger, logging.DEBUG)) def raise_my_exception(): raise MyException(\u0026#34;Fail\u0026#34;) @retry(stop=stop_after_attempt(3), after=after_log(logger, logging.DEBUG)) def raise_my_exception(): raise MyException(\u0026#34;Fail\u0026#34;) @retry(stop=stop_after_attempt(3), before_sleep=before_sleep_log(logger, logging.DEBUG)) def raise_my_exception(): raise MyException(\u0026#34;Fail\u0026#34;) 7. 统计异常情况 1 2 3 4 5 6 7 8 9 10 @retry(stop=stop_after_attempt(3)) def raise_my_exception(): raise MyException(\u0026#34;Fail\u0026#34;) try: raise_my_exception() except Exception: pass print(raise_my_exception.retry.statistics) 输出如下内容：\n1 {\u0026#39;start_time\u0026#39;: 283085.571804807, \u0026#39;attempt_number\u0026#39;: 3, \u0026#39;idle_for\u0026#39;: 0, \u0026#39;delay_since_first_attempt\u0026#39;: 0.0002240639878436923} 8. 自定义异常回调函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from tenacity import stop_after_attempt, retry_if_result, retry def return_last_value(retry_state): \u0026#34;\u0026#34;\u0026#34;return the result of the last call attempt\u0026#34;\u0026#34;\u0026#34; return retry_state.result() def is_false(value): \u0026#34;\u0026#34;\u0026#34;Return True if value is False\u0026#34;\u0026#34;\u0026#34; return value is False # will return False after trying 3 times to get a different result @retry(stop=stop_after_attempt(3), retry_error_callback=return_last_value, retry=retry_if_result(is_false)) def eventually_return_false(): return False print(eventually_return_false()) 输出结果为 False\n项目Git地址 https://github.com/jd/tenacity\n","date":"2018-12-19T11:15:00Z","permalink":"https://eryk-github-io.pages.dev/2018/12/19/python%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E4%BC%B4%E4%BE%A3--tenacity%E6%A8%A1%E5%9D%97%E4%BD%BF%E7%94%A8%E4%BB%8B%E7%BB%8D/","title":"Python异常处理伴侣 -- tenacity模块使用介绍"},{"content":"我的微信公众号：pyquant\n概念 虚拟合约是合约交易的买卖对象，是由合约交易所统一制定的，规定了某一特定的时间交割一定数量商品的标准化合约。\nOKEX的合约是OKEX推出的以BTC/LTC等币种进行结算的虚拟合约产品，每一张合约分别代表100美元的BTC，或10美元的其他币种（LTC,ETH等）,投资者可以通过买入做多合约来获取虚拟数字货币价格上涨的收益，或通过卖出做空来获取虚拟数字货币收益。合约的杠杆倍数为10或20倍。\nOKEX在设计虚拟合约时做了相应的调整，每一张合约代表价值100美元的比特币，这样的设计使得虚拟合约的杠杆倍数始终稳定在一个固定值，从而利于套保和套利。\nOKEX比特币虚拟合约的杠杆表现为法币收益层面的杠杆稳定：投入100美元，所能得到的收益=100美元 * 比特币的涨跌幅 * 固定的杠杆倍数。\n合约类型 目前OKEX根据合约时间长短提供三种合约交易，分别是当周、次周、季度。\n当周合约：指在距离交易日最近的北京时间周五下午4点进行交割的合约。 次周合约：指在距离交易日最近的北京时间第二个周五下午4点进行交割的合约。 季度合约：指交割日为3,6,9,12月中距离当前最近的一个月份的北京时间最后一个周五下午4点进行交割的合约。 新合约将于交割日当日下午16:10开始交易\n合约品种 BTC面值为100美元，报价时的最小变动单位为0.01美元,其他币种合约的面值为10美元，报价时的最小变动单位为0.001美元\nBTC、LTC、ETH、ETC、BCH、XRP、EOS、BTG\n交易规则 买入开多，卖出开空，买入平空，卖出平多\n开仓:\n未实现盈亏的计算公式：多仓未实现盈亏=（合约面值 / 结算基准价 - 合约面值 / 当前价格）* 持仓数量； 空仓未实现盈亏=（合约面值 / 当前价格 - 合约面值 / 结算基准价）* 持仓数量 平仓:\n已实现盈亏的计算公式：多仓已实现盈亏=（合约面值 / 结算基准价 -合约面值 /平仓价格） * 平仓数量； 空仓已实现盈亏=（合约面值 / 平仓价格-合约面值 /结算基准价）* 平仓数量 风控规则 全仓保证金制度、逐仓保证金制度、限价爆仓制度 全仓保证金制度与逐仓保证金制度，投资者二者只能选其一 全仓保证金: 当用户选择全仓保证金时，用户转入虚拟合约账户的所有余额，所有合约产生的盈亏都将作为合约的持仓保证金 全仓保证金模式下，开仓的要求是10倍杠杆开仓后，保证金率不低于90%，20倍杠杆开仓后，保证金率不低于80%\n所有虚拟合约账户中的BTC和LTC都将作为虚拟合约持仓的保证金，保证金数量将会随价格变化而变动。当虚拟合约价格朝着不利于投资者方向运动时，账户权益即会发生损失。当用户的保证金率变为0%时，账户即被爆仓，此时被爆仓的用户的损失接近或等于其虚拟合约账户中的所有资产。用户通过转入保证金和开仓合约的数量调整时机杠杆倍数。转入的保证金越多，开仓的合约数量越少，虚拟合约的实际杠杆倍数即越小，越不容易被爆仓。\n用户的保证金率=用户所有保证金/用户持仓所需的保证金-调整系数。在10倍杠杆时，合约的调整系数=10%，20倍杠杆时，合约的调整系数=20%；当保证金率小于等于0时，账户将被爆仓，所有仓位将被限价强平，未能强平的委托将在交割时进行爆仓分摊\n逐仓保证金制度：\n用户在合约开仓时所需要的保证金作为虚拟合约持仓的固定保证金，当虚拟合约价格发生变化时，保证金数值不发生变化。当虚拟合约价格朝向不利于用户方向运动时，未实现盈亏将发生损失。当用户的该合约该仓位的保证金率((固定保证金+未实现盈亏) * 开仓均价 * 杠杆 / (合约面值 * 持仓数量) - 调整系数；10倍杠杆，合约的调整系数=10%；20倍杠杆，合约的调整系数=20%，保证金率小于等于0%时，该合约的该仓位将被爆仓，此时被爆仓的用户损失接近或等于其该合约该方向仓位下的固定保证金。\n采用逐仓保证金模式时，每个合约的双向持仓将会独立计算其保证金和收益，只有开仓可用保证金大于等于开仓所需的保证金数量，用户才能进行委托。而逐仓保证金时，每个合约的开仓可用保证金可能不一致。\n委托方式 1. 计划委托 计划委托指令指的是预先设置委托和触发条件，当最新的成交价格达到事先设定的触发价格时，即会将事先设置的委托送入市场。\n2. 跟踪委托 跟踪委托指的是在行情发生较大幅度回调的情况下，将客户事先设定的委托送入市场的策略。当市场的最新价格达到投资者设定该策略后最高（最低）市场价格的（1±客户设定回调幅度）后，即会触发客户设定的策略，将客户事先设定的委托送入市场中。\n3. 冰山委托 冰山委托指的是投资者在进行大额交易时，为避免对市场造成过大冲击，将大单委托自动拆为多笔委托，根据当前的最新买一/卖一价格和客户设定的价格策略自动进行小单委托，在上一笔委托被全部成交或最新价格明显偏离当前委托价时，自动重新进行委托。\n4. 时间加权委托 时间加权委托指的是客户希望大额交易BTC时，为避免过大冲击成本，通过策略将大单拆细为多个小额委托，根据最新的对手方委托量自动选择委托量，主动与对手方成交进行连续买入的策略。\n保证金制度 10倍 20倍 手续费 开仓和平仓都征收手续费；若 maker 的手续费为负数，意味着您主动挂单为合约提供流动性，平台将赠送您手续费。合约交割手续费不受用户等级影响(BTC收取0.015%，非BTC收取0.05%)；爆仓导致的平仓不收手续费。\n等级 近30天交易量(BTC) 挂单成交手续费 吃单成交手续费\nLv1 \u0026lt;10000 0.03% 0.05%\nLv2 ≥10000 0.025% 0.045%\nLv3 ≥20000 0.02% 0.04%\nLv4 ≥30000 0.015% 0.035%\nLv5 ≥60000 0.01% 0.03%\nLv6 ≥100000 0.005% 0.025%\nLv7 ≥200000 0% 0.02%\nLv8 ≥300000 -0.01% 0.02%\n借币利息 计息规则：单笔借币订单独立计息。借币成功时首次计息，之后满24小时计息一次。每满15天，系统将未还清借币进行复息结算（未还利息计入下一阶段本金中），并开始下一阶段计息。\n还币规则：优先还最早生成的借币订单。优先还利息，再还本金。单笔借币订单的本金和应还利息全部还清后，单笔借币订单状态转换为已还清，随后此订单不再计息。\n借币日息usdt eth btc 0.1%，其他0.02%，不满一天按一天算\n爆仓 用户资产：本金+已借-已产生的利息\n负债：所有“已借”资产\n风险率=用户资产/负债\n当风险率跌到130%将有短信提示接近爆仓水平；当风险率跌到110%单仓将被强平。\n风险率：评估币币杠杆账户爆仓风险的指标。当风险率≥150%时，账户中多余的资产部分可通过资金划转转出；当风险率≤130%，风险率评估为风险，系统会给用户发短信提示风险；当风险率≤110%，系统将强制爆仓，并发短信告知用户。\n风险率计算公式：风险率=[(计价货币总资产-计价货币未还利息)/最新成交价+(交易货币总资产-交易货币未还利息)]/(计价货币借入资产/最新成交价+交易货币借入资产)*100%\n爆仓：当某币币杠杆账户的风险率≤110%时，系统会执行爆仓操作，使用该账户内所有资产去偿还借币债务。\n爆仓风险率=110%\n预计爆仓价格：在OKEx.com每一笔借币均须交纳一定比例的保证金，当市场发生不利变化，比如市场发生行情逆转，朝相反方向变化时，当前币币杠杆账户总资产缩水到一定限度时，系统会强制将该币币杠杆账户资产按市场最优价格以挂单形式卖出清算借币以及利息。\n预计爆仓价格计算公式：预计爆仓价格=(计价货币借入资产*爆仓风险率+计价货币未还利息-计价货币总资产)/(交易货币总资产-交易货币未还利息-交易货币借入资产*爆仓风险率)\n其他 合约限价机制\n新合约生成10分钟内：最高价=现货指数（1+5%），最低价=现货指数（1-5%）。 合约生成了10分钟后：最高价=近10分钟溢价平均值+现货指数（1+3%）,最低价=近10分钟溢价均值+现货指数（1-3%），溢价=合约价格-现货价格。 若计算后的价格超过最高偏离度的现货指数25%或价格小于0，则最高价=现货指数（1+25%），最低价=现货指数（1-25%）。 以上规则，开平仓都受限制，若开多或平空，当委托价高于最高价，则将触发限价；若开空或平多，当委托价低于最新价，则将触发限价。 术语 清算已实现盈亏：\n每周五下午4:00会进行清结算，需要每个合约的本周已实现盈亏结转到用户余额中，此部分金额可以用于开仓和提现。\n清算未实现盈亏：\n每周五下午4:00会进行清结算，若用户持有次周，季度合约的仓位，则需将仓位中未实盈亏结转到已实现盈亏中。\n爆仓平多/平空：\n逐仓：当用户将仓位中的”已用保证金“亏完时，则该仓位会被爆仓，系统将该持仓进行强制平仓.\n全仓：当用户将账户权益（存入金额+已实现盈亏+未实现盈亏）亏损完后，系统将用户的所有持仓进行强制平仓。\n交割平多/交割平空：\n当合约到期时（如每周五下午4:00当周合约到期），系统以最近一小时现货指数的算术平均值作为交割价对所有开仓的合约进行交割平仓，交割平仓后产生的盈亏部分加入已实现盈亏。\n爆仓平仓剩余：\n当用户爆仓时，系统会按爆仓价格进行强制平仓，但在撮合成交时可能与爆仓价格有所偏差，价格偏差所导致的盈余则称之为爆仓平仓剩余。\n穿仓分摊：\n当市场行情波动较大，用户爆仓后，按照爆仓价格无法成交时，导致亏损范围大于保证金。因此OKEX平台采用“分摊”制度，从本周盈利的用户中，每个人等比例分摊穿仓部分的损失。\n合约爆仓问题 https://support.okex.com/hc/zh-cn/articles/360000139652-%E5%90%88%E7%BA%A6%E7%88%86%E4%BB%93%E9%97%AE%E9%A2%98\n合约结算交割问题 交割规则有关于穿仓的介绍\nhttps://support.okex.com/hc/zh-cn/articles/360000105511-%E5%90%88%E7%BA%A6%E7%BB%93%E7%AE%97%E4%BA%A4%E5%89%B2%E9%97%AE%E9%A2%98\n","date":"2018-05-25T10:19:00Z","permalink":"https://eryk-github-io.pages.dev/2018/05/25/okex%E5%90%88%E7%BA%A6%E4%BA%A4%E6%98%93%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5%E4%BB%8B%E7%BB%8D/","title":"Okex合约交易基本概念介绍"},{"content":"一维零投资组合 先对股票按因子大小排序， nt是top，nb是bottom，nb中停牌的股票跳过停牌的股票，已纳入的股票如果停牌的也不能调出且需要保留仓位\n公式一：每只股票期末收益累加除以股票数 公式二：计算零投资组合当期收益 公式三：计算累计收益，把第一期净值作为1，连成每期收益率，最后减去1\n关键点 PE -\u0026gt; EP，使取值空间连续 停牌 复权（后复权） 自定义股票池 调仓周期 ","date":"2018-05-19T11:29:00Z","permalink":"https://eryk-github-io.pages.dev/2018/05/19/%E5%A6%82%E4%BD%95%E9%AA%8C%E8%AF%81%E5%9B%A0%E5%AD%90%E6%9C%89%E6%95%88%E6%80%A7-%E5%90%AC%E8%AF%BE%E7%AC%94%E8%AE%B0/","title":"《如何验证因子有效性》 听课笔记"},{"content":"最近在处理数字货币行情数据，使用websocket接收行情数据写入磁盘，发现运行时间久了偶尔出现socket close的异常，重试多次无效后程序异常退出，所以考虑将python程序作为linux 守护进程运行，了解了supervisord和systemd，决定使用更强大的systemd。\n基本概念 systemd 是一个 Linux 系统基础组件的集合，提供了一个系统和服务管理器，运行为 PID 1 并负责启动其它程序。功能包括：支持并行化任务；同时采用 socket 式与 D-Bus 总线式激活服务；按需启动守护进程（daemon）；利用 Linux 的 cgroups 监视进程；支持快照和系统恢复；维护挂载点和自动挂载点；各服务间基于依赖关系进行精密控制。systemd 支持 SysV 和 LSB 初始脚本，可以替代 sysvinit。除此之外，功能还包括日志进程、控制基础系统配置，维护登陆用户列表以及系统账户、运行时目录和设置，可以运行容器和虚拟机，可以简单的管理网络配置、网络时间同步、日志转发和名称解析等。\nsystemd架构图\n常用工具 systemd-analyze: 查看启动耗时 systemctl: 用来查看系统状态、启动停止服务，在systemctl参数中添加-H \u0026lt;用户名\u0026gt;@\u0026lt;主机名\u0026gt;可以实现对其他机器的远程控制。该过程使用ssh链接 journalctl: Systemd统一管理所有Unit的启动日志 unit 一个单元配置文件可以描述如下内容之一：系统服务(.service)、挂载点(.mount)、sockets(.sockets) 、系统设备(.device)、交换分区(.swap)、文件路径(.path)、启动目标(.target)、由 systemd 管理的计时器(.timer)\n如何编写服务脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 [Unit] Description=Network Manager Wants=network.target Before=network.target network.service [Service] Type=dbus BusName=org.freedesktop.NetworkManager ExecStart=/usr/sbin/NetworkManager --no-daemon # NM doesn\u0026#39;t want systemd to kill its children for it KillMode=process [Install] WantedBy=multi-user.target Alias=dbus-org.freedesktop.NetworkManager.service Also=NetworkManager-dispatcher.service 整个文件分三个部分，[Unit]·[Service]·[Install] [Unit]：记录unit文件的通用信息。\n[Service]：记录Service的信息\n[Install]：安装信息。\nUnit主要包含以下内容： ● Description：对本service的描述。\n● Before, After：定义启动顺序，Before=xxx.service，代表本服务在xxx.service启动之前启动。After=xxx.service,代表本服务在xxx之后启动。\n● Requires: 这个单元启动了，那么它“需要”的单元也会被启动; 它“需要”的单元被停止了，它自己也活不了。但是请注意，这个设定并不能控制某单元与它“需要”的单元的启动顺序（启动顺序是另外控制的），即 Systemd 不是先启动 Requires 再启动本单元，而是在本单元被激活时，并行启动两者。于是会产生争分夺秒的问题，如果 Requires 先启动成功，那么皆大欢喜; 如果 Requires 启动得慢，那本单元就会失败（Systemd 没有自动重试）。所以为了系统的健壮性，不建议使用这个标记，而建议使用 Wants 标记。可以使用多个 Requires。\n● RequiresOverridable：跟 Requires 很像。但是如果这条服务是由用户手动启动的，那么 RequiresOverridable 后面的服务即使启动不成功也不报错。跟 Requires 比增加了一定容错性，但是你要确定你的服务是有等待功能的。另外，如果不由用户手动启动而是随系统开机启动，那么依然会有 Requires 面临的问题。\n● Requisite：强势版本的 Requires。要是这里需要的服务启动不成功，那本单元文件不管能不能检测等不能等待都立刻就会失败。\n● Wants：推荐使用。本单元启动了，它“想要”的单元也会被启动。但是启动不成功，对本单元没有影响。\n● Conflicts：一个单元的启动会停止与它“冲突”的单元，反之亦然。\nService主要包含以下内容： ● Type：service的种类，包含下列几种类型：\n----simple 默认，这是最简单的服务类型。意思就是说启动的程序就是主体程序，这个程序要是退出那么一切都退出。 -----forking 标准 Unix Daemon 使用的启动方式。启动程序后会调用 fork() 函数，把必要的通信频道都设置好之后父进程退出，留下守护精灵的子进程 -----oneshot种服务类型就是启动，完成，没进程了。 notify,idle类型比较少见，不介绍。\n● ExecStart：服务启动时执行的命令，通常此命令就是服务的主体。\n------如果你服务的类型不是 oneshot，那么它只可以接受一个命令，参数不限。 ------多个命令用分号隔开，多行用 \\ 跨行。 ● ExecStartPre, ExecStartPost：ExecStart执行前后所调用的命令。\n● ExecStop：定义停止服务时所执行的命令，定义服务退出前所做的处理。如果没有指定，使用systemctl stop xxx命令时，服务将立即被终结而不做处理。\n● Restart：定义服务何种情况下重启（启动失败，启动超时，进程被终结）。可选选项：no, on-success, on-failure,on-watchdog, on-abort\n● SuccessExitStatus：参考ExecStart中返回值，定义何种情况算是启动成功。\neg：SuccessExitStatus=1 2 8 SIGKILL Install主要包含以下内容： ● WantedBy：何种情况下，服务被启用。\neg：WantedBy=multi-user.target（多用户环境下启用） ● Alias：别名\n例子 新建文件 /etc/systemd/system/huobi.service\n内容如下:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 [Unit] Description=huobi downloader After=rc-local.service [Service] Type=simple User=root Group=root WorkingDirectory=/usr/lib/code/atom ExecStart=/home/ubuntu/anaconda3/bin/python3.6 exchange/downloader.py huobi /data2/huobi/huobi.log Restart=always [Install] WantedBy=multi-user.target 观察系统日志，发现程序异常退出后systemd重启的了服务\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 root@ip-172-31-4-62:/usr/lib/code/atom# journalctl -u huobi.service -- Logs begin at Mon 2018-03-26 17:51:39 CST, end at Thu 2018-03-29 16:39:27 CST. -- Mar 29 10:58:46 ip-172-31-4-62 systemd[1]: Started huobi downloader. Mar 29 11:02:18 ip-172-31-4-62 systemd[1]: huobi.service: Main process exited, code=killed, status=9/KILL Mar 29 11:02:18 ip-172-31-4-62 systemd[1]: huobi.service: Unit entered failed state. Mar 29 11:02:18 ip-172-31-4-62 systemd[1]: huobi.service: Failed with result \u0026#39;signal\u0026#39;. Mar 29 11:02:18 ip-172-31-4-62 systemd[1]: huobi.service: Service hold-off time over, scheduling restart. Mar 29 11:02:18 ip-172-31-4-62 systemd[1]: Stopped huobi downloader. Mar 29 11:02:18 ip-172-31-4-62 systemd[1]: Started huobi downloader. Mar 29 11:29:58 ip-172-31-4-62 python3.6[9124]: Traceback (most recent call last): Mar 29 11:29:58 ip-172-31-4-62 python3.6[9124]: File \u0026#34;./exchange/ex_huobi.py\u0026#34;, line 66, in dispatch Mar 29 11:29:58 ip-172-31-4-62 python3.6[9124]: raw_data = await ws.recv() Mar 29 11:29:58 ip-172-31-4-62 python3.6[9124]: File \u0026#34;/home/ubuntu/anaconda3/lib/python3.6/site-packages/websockets/protocol.py\u0026#34;, line 323, i Mar 29 11:29:58 ip-172-31-4-62 python3.6[9124]: raise ConnectionClosed(self.close_code, self.close_reason) Mar 29 11:29:58 ip-172-31-4-62 python3.6[9124]: websockets.exceptions.ConnectionClosed: WebSocket connection is closed: code = 1006 (connection Mar 29 11:29:58 ip-172-31-4-62 systemd[1]: huobi.service: Service hold-off time over, scheduling restart. Mar 29 11:29:58 ip-172-31-4-62 systemd[1]: Stopped huobi downloader. Mar 29 11:29:58 ip-172-31-4-62 systemd[1]: Started huobi downloader. Mar 29 13:30:44 ip-172-31-4-62 python3.6[19180]: Traceback (most recent call last): Mar 29 13:30:44 ip-172-31-4-62 python3.6[19180]: File \u0026#34;./exchange/ex_huobi.py\u0026#34;, line 66, in dispatch Mar 29 13:30:44 ip-172-31-4-62 python3.6[19180]: raw_data = await ws.recv() Mar 29 13:30:44 ip-172-31-4-62 python3.6[19180]: File \u0026#34;/home/ubuntu/anaconda3/lib/python3.6/site-packages/websockets/protocol.py\u0026#34;, line 323, Mar 29 13:30:44 ip-172-31-4-62 python3.6[19180]: raise ConnectionClosed(self.close_code, self.close_reason) Mar 29 13:30:44 ip-172-31-4-62 python3.6[19180]: websockets.exceptions.ConnectionClosed: WebSocket connection is closed: code = 1006 (connectio Mar 29 13:30:45 ip-172-31-4-62 systemd[1]: huobi.service: Service hold-off time over, scheduling restart. Mar 29 13:30:45 ip-172-31-4-62 systemd[1]: Stopped huobi downloader. Mar 29 13:30:45 ip-172-31-4-62 systemd[1]: Started huobi downloader. 参考 https://wiki.archlinux.org/index.php/systemd_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)\nhttps://www.hi-linux.com/posts/3761.html\nhttps://blog.csdn.net/fu_wayne/article/details/38018825\n","date":"2018-03-29T09:57:00Z","permalink":"https://eryk-github-io.pages.dev/2018/03/29/systemd%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/","title":"systemd入门教程"},{"content":"我的微信公众号：pyquant\n逐笔成交： 交易过程中的单次成交，是交易过程的真实成交情况。这是Level-2的专有数据，用一个实例来解释这个概念：假设目前的卖一是10元、100手，这时有人以10元委托买入100手，那么这100手是如何成交的呢？这要取决于卖盘由几个委托单构成，如果卖一是一个委托单，那就是一笔成交，即100手；而如果卖一是由40手和60手两笔委托构成，那么这100股就会分成两次成交，即40手一次，60手一次，逐笔成交就是2笔。\n一般显示的数据格式为在几分几秒以多少价格分几笔成交了多少手。在这里我们要注意的是成交手数有时候是带小数点的，这是因为股票买进的股数最少是100股，委托的股数也应是100的整数倍，卖出却没有限制，因此成交的手数会有小数点。 另外一点就是如果在成交价格和手数前面没有显示，则一半是默认的1笔。\n分笔/分时成交： 3-5秒一次的行情采集期间累计的成交量和最后的成交价，可能是几笔成交的集合。这是大家长期以来唯一能看到的成交数据.\n一般显示的数据格式为在几分几秒以多少价格成交了多少手。**这里需要注意的是成交手数永远是整数，不会出现小数点数字。**其中现手累计数就是总手数。总手数也叫做成交量。有些软件在现量后面标注蓝色S和红色B，前者代表卖，后者代表买。（软件自己根据时间估计主动买还是主动卖）\n目前市面上出现了LEVEL-2行情数据，比较具有代表性的是大智慧，在那里把分笔成交是叫分时成交，实际上就是我们在普通分析软件上F1看到的“分笔成交明细”，但是他和LEVEL-2行情数据提供的逐笔成交明细是不一样的。**分笔数据由于是合成混合数据，它是以最后1笔的买卖方向来表示该时间内（3秒或者5秒）的买卖方向。**目前市面上的成交明细数据都是分笔成交，有些号称是LEVEL-2逐笔的明细数据其实也是分笔，即LEVEL-2行情软件里右侧小窗口显示的3秒分笔数据，虽然来自LEVEL-2行情，但仍然是分笔（分时）成交，而不是LEVEL-2行情软件里左侧显示的逐笔成交。因为左侧显示的逐笔成交在LEVEL-2行情软件里是不能保存的，也不能够导出供二次开发。能够导出的只有右侧小窗口里的分笔成交\n逐单/委托单： 我们每次向系统发出委托时，都有个委托合同编号，这个就是单。例如你一次买2000股股票，则是20手，那么这一单就是20手。但目前每种软件的推测统计都不一致，会导致不同软件显示数据出现差异。\n委托单的明细，这是交易所行情系统中没有发布的数据，还以刚才的例子说明，交易所只发出了40手和60手两笔成交（逐笔），并没有指出是一笔100手的买单吃掉了40手、60手两笔卖单。LEVEL-2行情能够根据成交的时间和队列等数据计算出全部已成交的委托单明细，这在交易分析中具有重大意义。（股票盘子越大，推测逐单数据误差越大,因为委托队列只显示前50个委托单;相对来说小盘股的DDE指标更为可靠）\n分时: 一般指一分钟成交集合;\n问题： 盘中数据的统计分析长期以来是对分时数据的统计分析，比如最简单的内盘和外盘，大单买入/卖出等，这种统计有两个明显的缺陷：\n第一、仅统计了主动成交方单方面的成交数据，而机构交易完全可能在被动成交方\n第二、分时数据不是真实的成交数据，大单不一定是大单，可能是很多散户在几秒中之内同时交易的结果，虽然使用level-2的逐笔成交来统计可以避免这一情况的发生，但立即就又产生了新的问题，即一笔真实的大单委托往往被分割成数笔成交，又捕捉不到真实的大单了。\n其他：一个孤独的数字是缺乏意义的，但是一些连续的数字则是充满想像的。一般来说，成交手数比较大而集中的时候，表示有大资金活跃迹象，该股出现价格异动的概率就大，应该引起投资者的注意。而如果半天也没人买或者都是一些小单子在交易，则至少短期不大可能成为好股。\n","date":"2018-03-29T09:57:00Z","permalink":"https://eryk-github-io.pages.dev/2018/03/29/%E9%80%90%E7%AC%94%E5%88%86%E7%AC%94%E9%80%90%E5%8D%95%E5%88%86%E6%97%B6%E6%95%B0%E6%8D%AE%E6%A6%82%E5%BF%B5%E5%8C%BA%E5%88%AB/","title":"逐笔，分笔，逐单，分时数据概念区别"},{"content":"比特币介绍 比特币（BitCoin）的概念最初由中本聪在2009年提出，根据中本聪的思路设计发布的开源软件以及建构其上的P2P网络。比特币是一种P2P形式的数字货币。点对点的传输意味着一个去中心化的支付系统。\n货币特征 去中心化：比特币是第一种分布式的虚拟货币，整个网络由用户构成，没有中央银行。去中心化是比特币安全与自由的保证 。 全世界流通：比特币可以在任意一台接入互联网的电脑上管理。不管身处何方，任何人都可以挖掘、购买、出售或收取比特币。 专属所有权：操控比特币需要私钥，它可以被隔离保存在任何存储介质。除了用户自己之外无人可以获取。 低交易费用：可以免费汇出比特币，但最终对每笔交易将收取约1比特分的交易费以确保交易更快执行。 无隐藏成本：作为由A到B的支付手段，比特币没有繁琐的额度与手续限制。知道对方比特币地址就可以进行支付。 跨平台挖掘：用户可以在众多平台上发掘不同硬件的计算能力。 比特币与分叉币比较 什么是挖矿 比特币是怎么产出的？\n首先我们来了解一下“区块链”，比特币的核心原理是“区块链”，每一个区块对应一个帐单，将所有的区块链接起来就是区块链，任何交易信息和转账记录都记录在区块链中。要注意的是区块链存在于整个互联网中，所以任何比特币持有者都不担心比特币遭受损失。\n每隔一个时间点，比特币系统会在系统节点上生成一个随机代码，互联网中的所有计算机都可以去寻找此代码，谁找到此代码，就会产生一个区块，随即得到一个比特币，这个过程就是人们常说的挖矿。\n挖矿设备介绍 现在市面上起码有几百种加密货币，主流的可以流通交易的也有不下20种。这么多的加密货币虽然都基于区块链技术，但不管是为了实现某些功能，还是为了形成差异，都会有所不同，从而导致挖不同的币使用的矿机也有所不同。通常来说，一台矿机只能挖一种或几种币，所以要挖什么比就要买什么型号的矿机。当然也存在全能选手，比如电脑就是，只是好多币种用电脑（CPU+显卡）挖的效率太低，无法盈利。\n矿机可以有多种分类方式，硬件上可以分为ASIC矿机、GPU矿机、FPGA矿机，以及玩客云那类CDN矿机等等。按照所有权划分，可以分为本地矿机和云矿机。\n首先，比特币（BTC）、以太坊（ETH）、比特币现金（BCH）、莱特币（LTC）、达世币（DASH）等主流币种，普遍采用PoW共识机制，挖矿就是通过贡献算力来维护网络安全、稳定的运行，并由此获得奖励币，所以都需要性能尽可能强大的矿机。但针对不同币种的算法，又细分出两种不同的矿机：ASIC矿机与GPU矿机。\n中本聪打造比特币的时候，希望比特币是一个去中心化的货币，不仅使用、交易如此，挖矿也应该如此。但是事与愿违，随着比特币等加密货币的价值越来越高，挖矿成为了一个产业，竞争越来越激烈，对挖矿算力的追求越来越高，所以从普通电脑挖矿，进化出了ASIC矿机与GPU矿机。\n主流矿机比较\n目前市场上最热门的矿机是蚂蚁矿机S9，具体配置如下\n矿池的选择 矿池的选择主要考虑以下两个因素：\n分配模式 手续费 分配模式说明： Slush方式 Slush矿池基于积分制，较老的shares将比新的shares拥有更低的权重，以减少一轮中切换矿池的投机分子。 2. Pay-Per-Share方式\n该方式为立即为每一个share支付报酬。该支出来源于矿池现有的比特币资金，因此可以立即取现，而不用等待区块生成完毕或者确认。这样可以避免矿池运营者幕后操纵。这中方法减少了矿工的风险，但将风险转移给了矿池的运营者。运营者可以收取手续费来弥补这些风险可能造成的损失 3. Luke-Jr方式\n该方式借用了其他方式的长处，如Slush方式一样，矿工需要提供工作证明来获得shares，如puddinpop方式一样，当区块生成时马上进行支付。但是不象之前的方式，针对一个区块的shares，会被再次利用于生成下一个区块。为了区分一下参与矿工的交易传输费用，只有当矿工的余额超过1BTC时才进行支付。如果没有达到1BTC，那么将在下一个区块生成时进行累计。如果矿工在一周内没有提供一个share，那么矿池会将剩下的余额进行支付，不管余额是多少。 4. Triplemining方式\n该方式是将一些中等大小矿池的计算力合并起来，然后将获得奖励的1%按照各个矿池计算力的比例分发给矿池运营者。 5. P2Pool方式\nP2Pool的挖矿节点工作在类似比特币区块链的一种shares链上。由于没有中心，所以也不会受到DoS攻击。和其他现有的矿池技术都不一样\u0026mdash;每个节点工作的区块，都包括支付给前期shares的所有者以及该节点自己的比特币。99%的奖励（注：50BTC+交易费用）会平均分给矿工，另外0.5%会奖励给生成区块的人。 6. Puddinpop方式\n一种使用“元哈希”技术的方式，使用特定的puddinpop挖矿软件，现在没有矿池用这种方式\n注意：\n一个share（注：贡献/股份）为一个矿池给客户端的一个合法的工作证明，这也同时是用来生成区块的工作证明，但是没有这么复杂，只需要很少的时间就能达到一个share。\n收益预测 蚂蚁矿机单机价格18000元，功率为1350w - 1512w，电费按0.3元/度计算，收益情况如下\n计算方式1 矿池算力排名 https://btc.com/stats/pool?pool_mode=day\n每十分钟产生一个区块，每个区块12.5个比特币，每天全球产生12.5*24*6=1800BTC\ns9算力13.5T，当前全网算力22.52EH/s，1E=1024P,1P=1024T,1T=1024G,一台s9一天产生的比特币是[13.5/(22.5210241024)]*1800≈.001029054BTC\n总收入\n13.5/(22.52*1024*1024) * 1800 * 65000 * 365 = 24414.295 元\n每天耗电36度，每年13140度电，电费约为 1.5*24*0.3 * 365 = 3942 元\n总利润为 24414.295 - 3942 = 20472.295 元\n计算方式2 挖矿算器\nhttps://btc.com/tools/mining-calculator\n参考 http://www.kuangjijia.com/category/492.html https://shop.bitmain.com/productDetail.htm?pid=00020180205094056650FrOW7847062D https://www.zhihu.com/question/20792042\n挖掘机哪家强？主流矿机比拼，蚂蚁矿机领先 http://www.sohu.com/a/155209866_114877 彩云评测：比特大陆蚂蚁S9比特币挖矿机 https://www.cybtc.com/article-2338-1.html 一个挖矿者血本无归的教训总结 http://www.hnr.cn/finance/zt/b/df/201706/t20170626_2980454.html\n","date":"2018-02-18T00:03:00Z","permalink":"https://eryk-github-io.pages.dev/2018/02/18/%E6%AF%94%E7%89%B9%E5%B8%81%E6%8C%96%E7%9F%BF/","title":"比特币挖矿"},{"content":"安装gitlab-runner https://docs.gitlab.com/runner/install/index.html\n国内镜像地址\nhttps://mirrors.tuna.tsinghua.edu.cn/help/gitlab-ci-multi-runner/\n注册Runner https://docs.gitlab.com/runner/register/\n步骤 注意：用户为root用户\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 root@sw:/home/sw# gitlab-runner register xuqi Running in system-mode. Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/): http://10.168.2.114/ Please enter the gitlab-ci token for this runner: 输入gitlab的token Please enter the gitlab-ci description for this runner: [sw]: xuqi Please enter the gitlab-ci tags for this runner (comma separated): Whether to lock the Runner to current project [true/false]: [true]: true Registering runner... succeeded runner=wzb81TcG Please enter the executor: docker, parallels, shell, virtualbox, docker+machine, kubernetes, docker-ssh, ssh, docker-ssh+machine: shell Runner registered successfully. Feel free to start it, but if it\u0026#39;s running already the config should be automatically reloaded! 注意： token位置在http://localhost/xxx/xxx/settings/ci_cd 页面里的Runners settings里\n如何删除在gitlab中不再使用的runner gitlab-runner verify \u0026ndash;delete\n关于executors的选择 https://docs.gitlab.com/runner/executors/README.html\n如何编写.gitlab-ci.yml 官方文档 https://gitlab.com/help/ci/yaml/README.md\nstages stages用来定义可以被job调用的stages。stages的规范允许有灵活的多级pipelines。\nJobs .gitlab-ci.yml允许指定无限量jobs。每个jobs必须有一个唯一的名字，而且不能是上面提到的关键字。job由一列参数来定义jobs的行为\ndemo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 image: python:3.6.1 before_script: - export BIZDATE=`date +%Y%m%d` - export PROJECT_NAME=$CI_PROJECT_NAME - export VERSION=$CI_COMMIT_TAG-$CI_COMMIT_SHA stages: - build - package - deploy build: stage: build script: - /home/gitlab-runner/anaconda3/bin/python3.6 -O -m compileall . - find . -name \u0026#39;*.pyc\u0026#39; -exec rename \u0026#39;s/.cpython-36.opt-1//\u0026#39; {} \\; - find . -name \u0026#39;*.pyc\u0026#39; -execdir mv {} .. \\; - find . -name \u0026#39;*.py\u0026#39; -type f -print -exec rm {} \\; - find . -name \u0026#39;__pycache__\u0026#39; -exec rm -rf {} \\; package: stage: package script: - rm -rf .git - rm -rf .gitlab-ci.yml - $(tar -zcf ../deploy-$VERSION.tar.gz .) - $(mkdir -p /home/gitlab-runner/backup/$PROJECT_NAME/$BIZDATE) - $(cp ../deploy-$VERSION.tar.gz /home/gitlab-runner/backup/$PROJECT_NAME/$BIZDATE/) - $(rm -rf ../deploy-$VERSION.tar.gz) - rm -rf . deploy: stage: deploy script: - echo \u0026#39;deploy\u0026#39; 服务器版本，使用脚本编写如上内容\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 before_script: - export PROJECT_NAME=$CI_PROJECT_NAME - export VERSION=$CI_COMMIT_TAG-$CI_COMMIT_SHA - export WORK_DIR=`pwd` - export HOST=\u0026#39;\u0026#39; stages: - deploy deploy: stage: deploy only: - /^release-.*$/ script: - ~/script/deploy.sh $WORK_DIR $HOST deploy.sh 脚本内容\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 workdir=$1 BIZDATE=`date +%Y%m%d` echo $workdir cd $workdir rm -rf .git rm -rf .gitlab-ci.yml tar -zcf ../bak-$VERSION.tar.gz . mkdir -p /home/gitlab-runner/backup/$PROJECT_NAME/$BIZDATE cp ../bak-$VERSION.tar.gz /home/gitlab-runner/backup/$PROJECT_NAME/$BIZDATE/ rm -rf ../bak-$VERSION.tar.gz /home/gitlab-runner/anaconda3/bin/python3.6 -O -m compileall . find . -name \u0026#39;*.pyc\u0026#39; -exec rename \u0026#39;s/.cpython-36.opt-1//\u0026#39; {} \\; find . -name \u0026#39;*.pyc\u0026#39; -execdir mv {} .. \\; find . -name \u0026#39;*.py\u0026#39; -type f -print -exec rm {} \\; find . -name \u0026#39;__pycache__\u0026#39; -exec rm -rf {} \\; #rm -rf $1/* tar -zcf ../deploy-$VERSION.tar.gz . for line in `cat hosts` do pem=`echo $line | cut -d \\: -f 1` host=`echo $line | cut -d \\: -f 2` echo $pem echo $host scp -i ~/keys/$pem ../deploy-$VERSION.tar.gz ubuntu@$host:/home/ubuntu/ done echo \u0026#39;finish\u0026#39; 参考 https://scarletsky.github.io/2016/07/29/use-gitlab-ci-for-continuous-integration/\nhttps://segmentfault.com/a/1190000010442764\n","date":"2018-02-05T11:35:00Z","permalink":"https://eryk-github-io.pages.dev/2018/02/05/gitlab-%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90/","title":"gitlab 持续集成"},{"content":"Filled相关Order类型： Market Order\n当订单规模很大时，broker可能会将订单拆分成多个规模较小的订单，导致以不同价格成交不同订单 bid-ask spreads 较大时风险较大 Limit Order\nSome brokers may charge different commissions between Market \u0026amp; Limit Orders. Market On Close(MOC) Order\nA Market-on-Close (MOC) order is a market order that is submitted to execute as close to the closing price as possible.\nLimit On Close(LOC) Order\nA Limit-on-close (LOC) order will be submitted at the close and will execute if the closing price is at or better than the submitted limit price.\nMarket On Open(MOO) Order\nA Market-on-Open (MOO) order combines a market order with the OPG time in force to create an order that is automatically submitted at the market\u0026rsquo;s open and fills at the market price.\nLimit On Open(LOO) Order\nA Limit-on-Open (LOO) order combines a limit order with the OPG time in force to create an order that is submitted at the market\u0026rsquo;s open, and that will only execute at the specified limit price or better. Orders are filled in accordance with specific exchange rules.\nMartet To Limit(MTL) Order\nA Market-to-Limit (MTL) order is submitted as a market order to execute at the current best market price. If the order is only partially filled, the remainder of the order is canceled and re-submitted as a limit order with the limit price equal to the price at which the filled portion of the order executed.\nIceberg/Reserve Orders\n提交大额股票、权证、期货和期权定单的投资者可能希望取消其定单的所有欲交易量以避免其他市场参与者可以预见并采取相应行动。冰山/保留属性（可在显示尺寸区域设置）可以帮助投资者以增量方式提交提交大宗定单，同时又只公开显示整体定单尺寸的某一特定部分。客户可以通过设置布局管理者或选择相应的区域向TWS的交易页面添加显示尺寸区域，输入定单时客户可以填充此项以显示整个定单的一部分。\nInvestors submitting large volume orders for stocks, warrants, futures and options may wish to conceal the full size of their order to avoid anticipatory action from other market participants. The Iceberg/Reserve attribute, applied through the Display Size field, provides a way to submit large volume orders to the market in increments while publicly displaying only a specified portion of the total order size. The Display Size field can be added to a trading page within TWS by configuring the Layout Manager and selecting the appropriate field, which can be user-populated at the time of order input, to display just a fraction of the entire order.\nTIMING / DURATION： 档提交一个订单后，当我们希望订单在指定时间内有效或订单的持续时间，可以使用如下订单类型\nDay Order\nA day order is an order to buy or sell a security that automatically expires if not executed on the day the order was placed. If it is not filled, it is canceled, and it is not filled if the limit or stop order price was not met during the trading session. It is one of several different order duration types that determines how long the order is in the market before it is canceled.\nGood Till Cancelled(GTC)\nA good \u0026rsquo;til canceled (GTC) order can be placed by an investor to buy or sell a security at a specified price that remains active until it is either rescinded by the investor or the trade is executed. GTC orders offer an alternative to placing a sequence of day orders, which expire at the end of each trading day. Rather than leave orders open ended, which poses the risk of being forgotten by investors until an eventual execution, GTC orders are commonly set to expire of 30 to 90 days after the trades are entered.\nGTC Buy Orders GTC Sell Orders Good Till Date/Time(GTD)\nThe GTD (Good-til-Date/Time) time in force lets you select an expiration date and time up until which an order will continue to work. Setting this attribute requires both a time in force selection of GTD, a date entry in the Expiration Date field, and a time entry in the Expiration Time field if that level of detail is required. Note that if you only enter a good-till date, the unfilled order will cancel at the close of the market on the specified day.\nTime Of Day Order\nAn order to buy or sell an asset that is placed at a specific time period during a trading session. A time-of-day order enters the market at a predetermined minute and remains good until canceled, unless otherwise specified.\nCONTIGENCY ORDERS 如果我们希望订单在满足某些特定条件才执行的话，特别是当你无法一直监视市场的时候。 这些订单类型允许交易者在一定条件满足时自动开仓或平仓。\nFill Or Kill(FOK): 全额即时订单\n全额即时订单也称为全部即刻执行否则撤销订单，指要求立即以特定的价格（通常只能为限价）予以执行，否则撤销订单。全额即时订单只能全部成交，而不能成交订单数量的一部分。\nFill or kill (FOK) is a type of time-in-force designation used in securities trading that instructs a brokerage to execute a transaction immediately and completely or not at all. This type of order is most likely to be used by active traders and is usually for a large quantity of stock. The order must be filled in its entirety or canceled (killed).\nFill And Kill(FAK): 非全额即时订单\n非全额即时订单指要求立即以特定的价格（可以为限价或市价）予以执行，否则撤销的订单。非全额即时订单允许部分成交，在部分成交时未成交的部分立刻撤销。\nImmediate Or Cancel(IOC)\nThe Immediate-or Cancel (IOC) time in force applied to an order dictates that any portion of the order that does not fill immediately will be canceled.\nAll Or None(AON)\nAll or none (AON) is an instruction used on a buy or sell order that instructs the broker to fill the order completely or not at all. ** If there are not enough shares available to fill the order completely, the order is canceled when the market closes. ** An AON order is considered a duration order because the investor provides instructions to the trader about how the order must be filled, which impacts how long the order remains active.\nFor Automatic OPENING of a Position Market If Touched(MIT) Order\n触价指令是指市场价格只要触及客户所规定的价格水平时就生效的指令。当市场价格触及指定价格时才执行买进或卖出动作。\nA Market if Touched (MIT) is an order to buy (or sell) an instrument below (or above) the market. Its purpose is to take advantage of sudden or unexpected changes in share or other prices and provides investors with a trigger price to set an order in motion. Investors may be waiting for excessive strength (or weakness) to cease, which might be represented by a specific price point. MIT orders can be used to determine whether or not to enter the market once a specific price level has been achieved. This order is held in the system until the trigger price is touched, and is then submitted as a market order. An MIT order is similar to a stop order, except that an MIT sell order is placed above the current market price, and a stop sell order is placed below.\nLimit If Touched(LIT) Order: 触及限价定单\n触及限价定单是一种以特定或更优的价格，以及低于（或高于）市价的价格买入（或卖出）金融产品的定单。这类定单被持有在系统中直到触发价格被触及。触及限价定单与限价止损定单相似，除了触及限价卖出定单以高于当前市场价格被下达，而限价止损卖出定单则是以低于市价被下达的。 使用触及限价定单帮助确保，如果定单被执行的话，定单将不会以劣于限价的价格执行。\nFor Automatic CLOSING of a Position Stop Order: 止损定单\n止损定单指令系统在用户指定的止损触发价格被达到提交一份买或卖的市价单。止损定单不担保某个特定的执行价格且有可能执行价格远离其止损价格。卖出止损定单总是以低于当前的市场价格下达，通常用于限制某个多头股票头寸的损失或保护其利润。买入止损定单总是以高于当前的市场价格下达，通常用于限制某个卖空头寸的损失或帮助其保护利润。\nStop Limit Order: 止损限价单\n止损限价单指令系统在用户指定的止损触发价格被触碰或超越时提交一份买或卖限价单。该定单由两个基本部分组成：止损价和限价。当一笔交易以止损价或通过止损价发生时，定单成为可执行的并以限价单（以某个特定的价格或更好的价格买入或卖出的定单）的形式进入市场。 止损限价单避免了止损单具有的价格风险（此风险是指不能担保执行价格），但投资人需承担即使在止损价格达到时定单仍不能执行的风险。投资人有可能完全“失去市场”。\nTrailing Stop Order: 追踪止损定单\n一个卖出追踪止损定单将止损价格设置为低于市场价格的一个固定金额，并带有附加的“追踪”金额。随着市场价格上涨，止损价格上涨的幅度为追踪金额，但如果股票价格下跌，止损价格不改变，当止损价格被触及时，一份市价定单将被提交。这种方法被设计用来允许投资者对可能损失的最大值指定限额，而不用对可能收益的最大值设定限额。“买入”追踪止损定单是卖出追踪止损定单的镜像，最适合用在下跌的市场中。\nTrailing Stop Limit Order: 追踪止损限价定单\n追踪止损限价定单允许投资者对可能损失的最大值指定限额，而不用对可能收益的最大值设定限额。追踪止损限价卖出定单与市场价格一起移动，并根据用户定义的“追踪”金额，连续地以低于市价的固定金额重新计算止损触发价格。限价定单价格同样根据限价抵消被连续地计算。随着市场价格上涨，止损价格和限价的上涨幅度分别为追踪金额和限价抵消，但如果股票价格下跌，止损价格保持不变，当止损价格被触及时，一份限价定单将以最后计算的限价被提交。追踪止损限价“买入”定单是追踪止损限价卖出定单的镜像，并通常被用在下跌的市场中。\nMore COMPLEX Types of Contingency Orders Conditional / Contingent Order\nBracketed Order: 括号定单\n括号定单旨在通过用两个方向相反的定单将定单“括”起来以帮助您限制损失、锁定利润。给买单加括号，使用的是一份高位卖出限价定单和一份低位卖出止损定单。给卖单加括号，使用的是一份高位买入止损定单和一份低位买入限价定单。 高位和低位括号定单的定单数量与最初的定单数量相匹配。默认情况下，括号定单从当前价格偏离1.0。您能够在特定定单的定单行上更改该偏离金额，也可使用全局配置中的定单预设功能修改产品、合约或策略的默认水平值。\nOne Cancels Other(OCO) \u0026amp; One Cancels All(OCA) Orders\nA one-cancels-the-other order (OCO) is a pair of orders stipulating that if one order is executed, then the other order is automatically canceled. A one-cancels-the-other order (OCO) combines a stop order with a limit order on an automated trading platform. When either the stop or limit level is reached and the order executed, the other order will be automatically canceled. Seasoned traders use OCO orders to mitigate risk. one-Cancels All (OCA) order type allows an investor to place multiple and possibly unrelated orders assigned to a group. The aim is to complete just one of the orders, which in turn will cause TWS to cancel the remaining orders. The investor may submit several orders aimed at taking advantage of the most desirable price within the group. Completion of one piece of the group order causes cancellation of the remaining group orders while partial completion causes the group to rebalance. An investor might desire to sell 1000 shares of only ONE of three positions held above prevailing market prices. The OCA order group allows the investor to enter prices at specified target levels and if one is completed, the other two will automatically cancel. Alternatively, an investor may wish to take a LONG position in eMini S\u0026amp;P stock index futures in a falling market or else SELL US treasury futures at a more favorable price. Grouping the two orders using an OCA order type offers the investor two chances to enter a similar position, while only running the risk of taking on a single position.\nOne Triggers Other(OTO) \u0026amp; One Triggers All(OTA) Orders\n订单优先原则 价格优先原则\n价格优先原则指交易所（或做市商）在对投资者的订单进行撮合时，按照价格的高低原则进行排序，较高价格的买进订单优先于较低价格的买进订单，较低价格的卖出订单优先于较高价格的卖出订单。\n时间优先原则\n按比例分配原则是指所有订单在价格相同的情况下，成交数量基于订单数量按比例进行分配。纽约证券交易所的大厅交易、芝加哥期权交易所等采取了按比例分配的订单优先原则。\n按比例分配原则\n按比例分配原则是指所有订单在价格相同的情况下，成交数量基于订单数量按比例进行分配。纽约证券交易所的大厅交易、芝加哥期权交易所等采取了按比例分配的订单优先原则。\n数量优先原则\n在价格一样、甚至价格一样且无法区分时间先后的情况下，有些交易所规定应遵循数量优先原则。数量优先原则而有两种形式，一是在订单价格相同且时间也相同的情况下，订单数量较大者优先于订单数量较小者；二是在数量上完全匹配的订单（即买进订单和卖出订单在数量上相等）优先于数量不一致的订单。第一种形式使得经纪商优先处理数量较大的订单，因而提高了流动性；第二种形式则减少了订单部分执行的情况。\n客户优先原则\n客户优先原则通常指在同一价格条件下，公共订单优先于经纪商自营账户的订单。纽约证券交易所采取这一原则，客户的订单优先于专家的订单。客户优先原则减轻了客户与经纪商自营之间的利益冲突。\n参考 https://www.interactivebrokers.com/cn/index.php?f=3361 https://www.zhihu.com/question/23667442\n","date":"2018-01-13T19:05:00Z","permalink":"https://eryk-github-io.pages.dev/2018/01/13/%E4%BA%A4%E6%98%93%E8%AE%A2%E5%8D%95%E7%B1%BB%E5%9E%8B%E4%BB%8B%E7%BB%8D/","title":"交易订单类型介绍"},{"content":"资源 https://github.com/kennethreitz/awesome-coins\n数据 https://www.cryptocompare.com/api Cryptocurrency data API for over 40 exchanges and 600 coins(BTC,ETH,XMR + 600 other cryptos)\nGet open, high, low, close, volumefrom and volumeto from the each minute historical data. This data is only stored for 7 days, if you need more,use the hourly or daily path. It uses BTC conversion if data is not available because the coin is not trading in the specified currency\nhttps://bitcoincharts.com/about/markets-api/ Bitcoincharts\u0026rsquo; API is accessable through HTTP Parameters are passed using GET-requests returned data is JSON encoded Don\u0026rsquo;t query more often than once every 15 minutes!\nTrade data is available as CSV, delayed by approx. 15 minutes. It will return the 2000 most recent trades.\nhttp://api.bitcoincharts.com/v1/csv/\nhttps://www.coinigy.com/bitcoin-data/\nhttps://www.quora.com/Where-can-I-get-per-tick-historical-bitcoin-price-data\nhttps://coinmarketcap.com/historical/\nhttps://github.com/CoinCapDev/CoinCap.io\nhttp://www.yucezhe.com/product/data#!?series=digital_currency\n回测\u0026amp;交易 https://github.com/CoinTK/CoinTK Bitcoin Trading Algorithm Backtesting and Analysis Toolkit\nhttps://gekko.wizb.it/docs/introduction/about_gekko.html A bitcoin trading bot written in node - https://gekko.wizb.it/\nhttps://cryptotrader.org/\nhttp://www.abuquant.com/lecture/lecture_10.html\n比特币, 莱特币的走势数据分析 http://www.abuquant.com/\nhttps://github.com/ctubio/Krypto-trading-bot Self-hosted crypto trading bot (automated high frequency market making) in node.js, angular, typescript and c++ https://127.0.0.1:3000\nhttps://www.kaggle.com/smitad/bitcoin-trading-strategy-simulation API Python https://python-binance.readthedocs.io/en/latest/overview.html\nbinance\nJava https://github.com/timmolter/XChange\nXChange is a Java library providing a streamlined API for interacting with 60+ Bitcoin and Altcoin exchanges providing a consistent interface for trading and accessing market data.\nhttps://www.botvs.com/api\n源码实现 https://github.com/bisq-network/exchange\nThe decentralized bitcoin exchange https://bisq.network\nhttps://github.com/bitcoin/bitcoin\nBitcoin Core integration/staging tree\nhttps://github.com/jamesob/tinychain\nA pocket-sized implementation of Bitcoin\n","date":"2017-12-22T23:25:00Z","permalink":"https://eryk-github-io.pages.dev/2017/12/22/%E6%AF%94%E7%89%B9%E5%B8%81%E8%B5%84%E6%BA%90%E6%94%B6%E9%9B%86/","title":"比特币资源收集"},{"content":"magic functions: %time: 记录script运行时间 %timeit: 循环n次，记录平均执行时间 %run \u0026amp; %prun: 分析script的执行效率 %lprun: 分析一条语句在function中执行效率 %mprun: 查看script脚本使用内存量 %memit: 循环n次，记录平均内存使用量 安装 1 2 3 4 pip install jupyter_contrib_nbextensions pip install line-profiler pip install psutil pip install memory_profiler jupyter load 插件 1 2 %load_ext line_profiler %load_ext memory_profiler Time Profiling time \u0026amp; timeit 1 2 3 4 5 6 7 8 9 In [7]: %time {1 for i in xrange(10*1000000)} CPU times: user 0.72 s, sys: 0.16 s, total: 0.88 s Wall time: 0.75 s In [8]: %timeit 10*1000000 10000000 loops, best of 3: 38.2 ns per loop In [9]: %timeit -n 1000 10*1000000 1000 loops, best of 3: 67 ns per loop %prun 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 In [10]: from time import sleep In [11]: def foo(): sleep(1) In [12]: def bar(): sleep(2) In [13]: def baz(): foo(), bar() In [14]: %prun baz() 7 function calls in 3.001 seconds Ordered by: internal time ncalls tottime percall cumtime percall filename:lineno(function) 2 3.001 1.500 3.001 1.500 {time.sleep} 1 0.000 0.000 3.001 3.001 \u0026lt;ipython-input-17-c32ce4852c7d\u0026gt;:1(baz) 1 0.000 0.000 2.000 2.000 \u0026lt;ipython-input-11-2689ca7390dc\u0026gt;:1(bar) 1 0.000 0.000 1.001 1.001 \u0026lt;ipython-input-10-e11af1cc2c91\u0026gt;:1(foo) 1 0.000 0.000 3.001 3.001 \u0026lt;string\u0026gt;:1(\u0026lt;module\u0026gt;) 1 0.000 0.000 0.000 0.000 {method \u0026#39;disable\u0026#39; of \u0026#39;_lsprof.Profiler\u0026#39; objects} Memory Profiling %mprun 1 2 3 4 5 6 7 8 9 10 11 12 13 In [17]: %mprun -f foo foo(100000) Filename: foo.py Line # Mem usage Increment Line Contents ================================================ 1 20.590 MB 0.000 MB def foo(n): 2 20.590 MB 0.000 MB phrase = \u0026#39;repeat me\u0026#39; 3 21.445 MB 0.855 MB pmul = phrase * n 4 25.020 MB 3.574 MB pjoi = \u0026#39;\u0026#39;.join([phrase for x in xrange(n)]) 5 25.020 MB 0.000 MB pinc = \u0026#39;\u0026#39; 6 43.594 MB 18.574 MB for x in xrange(n): 7 43.594 MB 0.000 MB pinc += phrase 8 41.102 MB -2.492 MB del pmul, pjoi, pinc 在jupyter中运行报如下错误：\n1 2 ERROR: Could not find file \u0026lt;ipython-input-10-6aab78230286\u0026gt; NOTE: %mprun can only be used on functions defined in physical files, and not in the IPython environment. %memit 1 2 In [18]: %memit -r 3 [x for x in xrange(1000000)] maximum of 3: 75.320312 MB per loop 参考 http://jupyter-contrib-nbextensions.readthedocs.io/en/latest/install.html#install-the-python-package\nhttp://mortada.net/easily-profile-python-code-in-jupyter.html\nhttps://www.dataquest.io/blog/jupyter-notebook-tips-tricks-shortcuts/\nhttp://pynash.org/2013/03/06/timing-and-profiling/\nhttp://nbviewer.jupyter.org/gist/jiffyclub/3062428\nhttp://www.xavierdupre.fr/app/mlstatpy/helpsphinx/notebooks/completion_profiling.html\nhttps://pypi.python.org/pypi/memory_profiler/0.41\nhttps://github.com/rkern/line_profiler\n","date":"2017-12-05T12:18:00Z","permalink":"https://eryk-github-io.pages.dev/2017/12/05/jupyter%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7/","title":"jupyter性能分析工具"},{"content":"制作启动盘 下载 RASPBIAN STRETCH WITH DESKTOP，地址如下 https://www.raspberrypi.org/downloads/raspbian/\n使用SDFormatter 格式化sd卡 使用win32diskimager将 .img文件写入sd卡 安装kodi 参考如下步骤\nhttp://kodi.wiki/view/HOW-TO:Install_Kodi_on_Raspberry_Pi\nmac 添加nfs服务 在 /etc/exports 文件中添加如下内容，IP地址为树莓派ip地址\n/Users/eryk/Documents/movie 192.168.1.10 (rw)\n然后启动nfs服务，树莓派可以从mac目录读取视频文件\n1 2 3 sudo nfsd enable sudo nfsd update sudo nfsd status 树莓派开机mount nfs目录 使用如下命令mount nfs 目录\nsudo mount 192.168.1.4:/Users/eryk/Documents/movie /home/pi/movie\n如果想在树莓派开机启动自动mount nfs目录，需要在/etc/fstab中添加如下设置\n192.168.1.4:/Users/eryk/Documents/movie /home/pi/movie nfs defaults 0 0\nkodi设置中文 system–\u0026gt;settings–\u0026gt;Interface–\u0026gt;skin，把 fonts 改成 Arial based； system–\u0026gt;settings–\u0026gt;Interface–\u0026gt;Regional，改Language改成Chinese(Simple) ","date":"2017-12-03T14:26:00Z","permalink":"https://eryk-github-io.pages.dev/2017/12/03/%E4%BD%BF%E7%94%A8%E6%A0%91%E8%8E%93%E6%B4%BE-kodi%E6%90%AD%E5%BB%BA%E5%A4%9A%E5%AA%92%E4%BD%93%E7%8E%AF%E5%A2%83/","title":"使用树莓派+kodi搭建多媒体环境"},{"content":"转自：http://www.dataivy.cn/blog/data_etl/?wt_tb=1%7C1511709850969\n当数据质量校验完成后，针对有问题的数据要进行的是数据清洗和转换，另外还包括对正常数据的转换。数据清洗的主要作用包括：纠正错误、删除重复项、统一规格、修正逻辑、转换构造和数据压缩。\n1. 纠正错误 错误数据是数据源环境中经常出现的一类问题。数据错误的形式包括：\n数据值错误：数据直接是错误的，例如超过固定域集、超过极值、拼写错误、属性错误、源错误等。 数据类型错误：数据的存储类型不符合实际情况，如日期类型的以数值型存储，时间戳存为字符串等。 数据编码错误：数据存储的编码错误，例如将UTF-8写成UTF-80。 数据格式错误：数据的存储格式问题，如半角全角字符、中英文字符等。 数据异常错误：如数值数据输成全角数字字符、字符串数据后面有一个回车操作、日期越界、数据前后有不可见字符等。 依赖冲突：某些数据字段间存储依赖关系，例如城市与邮政编码应该满足对应关系，但可能存在二者不匹配的问题。 多值错误：大多数情况下，每个字段存储的是单个值，但也存在一个字段存储多个值的情况，其中有些可能是不符合实际业务规则的。 这类错误产生的原因是业务系统不够健全，尤其是在数据产生之初的校验和入库规则不规范，导致在接收输入后没有进行判断或无法检测而直接写入后台数据库造成的。 2. 删除重复项 由于各种原因，数据中可能存在重复记录或重复字段（列），对于这些重复项目（行和列）需要做去重处理。\n对于重复项的判断，基本思想是“排序和合并”，先将数据库中的记录按一定规则排序，然后通过比较邻近记录是否相似来检测记录是否重复。这里面其实包含了两个操作，一是排序，二是计算相似度。\n常见的排序算法：\n插入排序 冒泡排序 选择排序 快速排序 堆排序 归并排序 基数排序 希尔排序 常见的判断相似度的算法：\n基本的字段匹配算法 标准化欧氏距离 汉明距离 夹角余弦 杰卡德距离 马氏距离 曼哈顿距离 闵可夫斯基距离 欧氏距离 切比雪夫距离 相关系数 信息熵 对于重复的数据项，尽量需要经过业务确认并进行整理提取出规则。在清洗转换阶段，对于重复数据项尽量不要轻易做出删除决策，尤其不能将重要的或有业务意义的数据过滤掉，校验和重复确认的工作必不可少。\n3. 统一规格 由于数据源系统分散在各个业务线，不同业务线对于数据的要求、理解和规格不同，导致对于同一数据对象描述规格完全不同，因此在清洗过程中需要统一数据规格并将一致性的内容抽象出来。\n数据字段的规则大致可以从以下几个方面进行统一：\n名称，对于同一个数据对象的名称首先应该是一致的。例如对于访问深度这个字段，可能的名称包括访问深度、人均页面浏览量、每访问PV数。 类型：同一个数据对象的数据类型必须统一，且表示方法一致。例如普通日期的类型和时间戳的类型需要区分。 单位：对于数值型字段，单位需要统一。例如万、十万、百万等单位度量。 格式：在同一类型下，不同的表示格式也会产生差异。例如日期中的长日期、短日期、英文、中文、年月日制式和缩写等格式均不一样。 长度：同一字段长度必须一致。 小数位数：小数位数对于数值型字段尤为重要，尤其当数据量累积较大时会因为位数的不同而产生巨大偏差。 计数方法：对于数值型等的千分位、科学计数法等的计数方法的统一。 缩写规则：对于常用字段的缩写，例如单位、姓名、日期、月份等的统一。例如将周一表示为Monday还是Mon还是M。 值域：对于离散型和连续型的变量都应该根据业务规则进行统一的值域约束。 约束：是否允许控制、唯一性、外键约束、主键等的统一。 统一数据规格的过程中，需要重要的一点是确认不同业务线带来数据的规格一致性，这需要业务部门的参与、讨论和确认，以明确不同体系数据的统一标准。\n4. 修正逻辑 在多数据源的环境下，很可能存在数据异常或冲突的问题。\n例如不同的数据源对于订单数量的数据统计冲突问题，结果出现矛盾的记录。通常，这是由于不同系统对于同一个数据对象的统计逻辑不同而造成的，逻辑的不一致会直接导致结果的差异性；除了统计逻辑和口径的差异，也有因为源数据系统基于性能的考虑，放弃了外键约束，从而导致数据不一致的结果；另外，也存在极小的数据丢失的可能性，通常由于并发量和负载过高、服务器延迟甚至宕机等原因导致的数据采集的差异。\n对于这类的数据矛盾，首先需要明确各个源系统的逻辑、条件、口径，然后定义一套符合各个系统采集逻辑的规则，并对异常源系统的采集逻辑进行修正。\n某些情况下，也可能存在业务规则的错误导致的数据采集的错误，此时需要从源头纠正错误的采集逻辑，然后再进行数据清洗和转换。\n5. 转换构造 数据变换是数据清理过程的重要步骤，是对数据的一个的标准的处理，几乎所有的数据处理过程都会涉及该步骤。数据转换常见的内容包括：数据类型转换、数据语义转换、数据值域转换、数据粒度转换、表/数据拆分、行列转换、数据离散化、数据离散化、提炼新字段、属性构造、数据压缩等。\n数据类型转换 当数据来自不同数据源时，不同类型的数据源数据类型不兼容可能导致系统报错。这时需要将不同数据源的数据类型进行统一转换为一种兼容的数据类型。\n数据语义转换 传统数据仓库中基于第三范式可能存在维度表、事实表等，此时在事实表中会有很多字段需要结合维度表才能进行语义上的解析。例如，假如字段M的业务含义是浏览器类型，其取值分为是1/2/3/4/5，这5个数字如果不加转换则很难理解为业务语言，更无法在后期被解读和应用。\n数据粒度转换 业务系统一般存储的是明细数据，有些系统甚至存储的是基于时间戳的数据，而数据仓库中的数据是用来分析的，不需要非常明细的数据，一般情况下，会将业务系统数据按照数据仓库中不同的粒度需求进行聚合。\n表/数据拆分 某些字段可能存储多中数据信息，例如时间戳中包含了年、月、日、小时、分、秒等信息，有些规则中需要将其中部分或者全部时间属性进行拆分，以此来满足多粒度下的数据聚合需求。同样的，一个表内的多个字段，也可能存在表字段拆分的情况。\n行列转换 某些情况下，表内的行列数据会需要进行转换（又称为转置），例如协同过滤的计算之前，user和term之间的关系即互为行列并且可相互转换，可用来满足基于项目和基于用户的相似度推荐计算。\n数据离散化 将连续取值的属性离散化成若干区间，来帮助消减一个连续属性的取值个数。例如对于收入这个字段，为了便于做统计，根据业务经验可能分为几个不同的区间：0～3000、3001～5000、5001～10000、10001～30000、大于30000，或者在此基础上分别用1、2、3、4、5来表示。\n数据标准化 不同字段间由于字段本身的业务含义不同，有些时间需要消除变量之间不同数量级造成的数值之间的悬殊差异。例如将销售额进行离散化处理，以消除不同销售额之间由于量级关系导致的无法进行多列的复合计算。数据标准化过程还可以用来解决个别数值较高的属性对聚类结果的影响。\n提炼新字段 很多情况下，需要基于业务规则提取新的字段，这些字段也称为复合字段。这些字段通常都是基于单一字段产生，但需要进行复合运算甚至复杂算法模型才能得到新的指标。\n属性构造 有些建模过程中，也会需要根据已有的属性集构造新的属性。例如，几乎所有的机器学习都会讲样本分为训练集、测试集、验证集三类，那么数据集的分类（或者叫分区）就属于需要新构建的属性，用户做机器学习不同阶段的样本使用。\n提示 在某些场景中，也存在一些特殊转换方法。例如在机器学习中，有些值是离散型的数据但存在一定意义，例如最高学历这个字段中包含博士、研究生、大学、高中这4个值，某些算法不支持直接对文本进行计算，此时需要将学历这个字段进行转换。常见的方法是将值域集中的每个值拆解为一个字段，每个字段取值为0或1（布尔型或数值型）。这时，就会出现4个新的字段，对于一条记录来看（通常是一个人），其最高学历只能满足一个，例如字段博士为1，那么其余的字段（研究生、大学、高中）则为0。因此这个过程实际上是将1个字段根据值域（4个值的集合）拆解为4个字段。\n6. 数据压缩 数据压缩是指在保持原有数据集的完整性和准确性，不丢失有用信息的前提下，按照一定的算法和方式对数据进行重新组织的一种技术方法。\n对大规模的数据进行复杂的数据分析与数据计算通常需要耗费大量时间，所以在这之前需要进行数据的约减和压缩，减小数据规模，而且还可能面临交互式的数据挖掘，根据数据挖掘前后对比对数据进行信息反馈。这样在精简数据集上进行数据挖掘显然效率更高，并且挖掘出来的结果与使用原有数据集所获得结果基本相同。\n数据压缩的意义不止体现在数据计算过程中，还有利于减少存储空间，提高其传输、存储和处理效率，减少数据的冗余和存储的空间，这对于底层大数据平台具有非常重要的意义。\n数据压缩有多种方式可供选择：\n数据聚合：将数据聚合后使用，例如如果汇总全部数据，那么基于更粗粒度的数据更加便利。 维度约减：通过相关分析手动消除多余属性，使得参与计算的维度（字段）减少；也可以使用主成分分析、因子分析等进行维度聚合，得到的同样是更少的参与计算的数据维度。 数据块消减：利用聚类或参数模型替代原有数据，这种方式常见于多个模型综合进行机器学习和数据挖掘。 数据压缩：数据压缩包括无损压缩和有损压缩两种类型。数据压缩常用于磁盘文件、视频、音频、图像等。 ","date":"2017-11-30T15:39:00Z","permalink":"https://eryk-github-io.pages.dev/2017/11/30/%E6%95%B0%E6%8D%AE%E9%A2%84%E5%A4%84%E7%90%86-%E6%B8%85%E6%B4%97%E8%BD%AC%E6%8D%A2/","title":"数据预处理-清洗转换"},{"content":"深圳市价委托的类型有五种，分别为：对手方最优价格、本方最优价格、最优五档即时成交剩余撤销、即时成交剩余撤销（FAK）、全额成交或撤销委托（FOK）。\n对手方最优价格委托 对手方最优价格委托指投资者无须指定委托价格，当委托申报指令进入交易主机时，交易主机以当时集中申报簿有效竞价范围内对手方队列的最优价格为其指定价格的委托类型。\n“对手方最优价格委托”无需输入指定价格，如果当时交易主机中集中申报簿的对手方队列中存在有效申报，则与当时对手方队列中价格最优的申报成交；“价格最优的申报”是指集中申报簿中买方“买一”队列或卖方“卖一”队列。 没有完全成交的“对手方最优价格委托”将以限价形式保存在交易主机集中申报簿的本方队列中，其指定价格为委托已成交部分的成交价，也就是委托申报进入交易主机当时对手方队列的最优价格. 如果当时集中申报簿中对手方队列没有有效对手盘，交易主机直接对“对手方最优价格委托”作撤单处理。 本方最优价格委托 本方最优价格委托是指投资者无须指定委托价格，当委托申报指令进入交易主机时，交易主机以当时集中申报簿有效竞价范围内本方队列最优价格为其指定价格的委托类型。\n“本方最优价格委托”无需输入指定价格，如果当时交易主机中集中申报簿的本方队列存在有效申报，则以当时本方队列的最优价格为指定价格以限价形式保存在交易主机的集中申报簿中； 如果当时集中申报簿本方队列中没有有效申报，交易主机对“本方最优价格委托”作撤销处理。 即时成交剩余撤销委托 即时成交剩余撤销委托是指无需指定委托价格，委托进入交易主机时能立即成交部分即予以撮合，未成交部分立即自动撤销的委托方式，一笔委托可以同对手方数笔不同价格的委托撮合成交。\n“即时成交剩余撤销委托”无需指定价格，如果当时交易主机集中申报簿的对手方队列中存在有效申报，则按对手方申报队列顺序以对手方价格为成交价进行逐笔配对； “即时成交剩余撤销委托”可以与不同价格的对手方委托撮合成交，直至无有效对手盘（即在涨跌幅限制范围内或在最后一笔成交价为基础的有效竞价范围内交易主机中现有的对手方队列中无委托）； 若“即时成交剩余撤销委托”成交后有剩余的委托（包括部分成交、未有成交的情形），交易主机立即对剩余部分作撤单处理。 最优五档即时成交剩余撤销委托 “最优五档即时成交剩余撤销委托”是为了避免市场价格波动过大而对“即时成交剩余撤销委托”的改良。其与“即时成交剩余撤销委托”方式的区别就在于“即时成交剩余撤销委托”可以与对手方数笔不同价格的委托撮合，直至无有效对手盘，而“最优五档即时成交剩余撤销委托”只能与一定范围内的对手方队列成交。\n全额成交或撤销委托 全额成交或撤销委托是指无需指定委托价格，委托进入交易主机时能立即全部成交即予以撮合，否则委托全部撤销的委托方式，该委托可以与对手方数笔不同价格的委托撮合成交。\n问题 市价委托可以撤单吗\n根据《深圳证券交易所交易规则》，市价申报主要包括：对手方最优价格申报、本方最优价格申报、最优五档即时成交剩余撤销申报、即时成交剩余撤销申报、全额成交或撤销申报等五种，其中对手方最优价格申报和本方最优价格申报部分成交时，未成交部分可以主动撤单，其余情况主机会自动撤单，而不能主动撤单。\n测试结果 市价委托(深圳对方最优价格) 买入: 按照涨停价下单 卖出: 按照价格0下单 市价委托(深圳本方最优价格) 买入: 按照买一价下单，按照时间优先原则排列订单 卖出: 按照卖一价下单，按照时间优先原则排列订单 市价委托(深圳即时成交剩余撤销) 买入: 按照涨停价下单 市价委托(上海五档即成剩撤 / 深圳五档即成剩撤) 卖出： 按照价格0下单 市价委托(深圳全额成交或撤销) 买入: 按照涨停价下单，买入量大于5档时还会继续买入 市价委托(上海五档即成转限价) 参考 深圳证券交易所关于五种市价委托方式的业务说明 http://www.szse.cn/UpFiles/Attach/1045/2005/11/14/1442302347.doc\n","date":"2017-11-24T09:29:00Z","permalink":"https://eryk-github-io.pages.dev/2017/11/24/%E6%B7%B1%E5%9C%B3%E5%B8%82%E4%BB%B7%E5%A7%94%E6%89%98%E7%9A%84%E7%B1%BB%E5%9E%8B/","title":"深圳市价委托的类型"},{"content":"TradeX 是为从事股票程序化交易的投资者提供一个接口，通过将自己的交易策略编写成计算机代码，实现自动 自动快速读取行情进行分析，以及股票下单、撤单、查询，做到股票的全自动买卖。\n优势\n多语言支持: 封装 C++,C#，Python，Delphi，Java，VB 支持 Level 2 行情(专用账户版，用户需自行购买通达信 Level2 行情账户)包含十档行情、逐笔成交、买卖队列和深圳逐笔委托行情(上交所不对外提供逐笔委托)，需开通通达信的 Level 2 金融终端账户 支持扩展行情: 包含期货、期权、三版、港股数据 支持股票五档实时行情，实测速度比 TdxhqApi 快 10%~30%;包含各周期 K 线、分时、分笔成交，五档行情，F10 公司信息资料 社区活跃 支持市场上绝大部分券商 接口是 tcp 直连获取行情 劣势:\n所有行情接口均要求客户端主动查询请求行情数据，而非推送行情;每种行情接口各自对应于不同的通讯协议。每种行情接口的都可以建立单连接和批量多连接;如果要快速获取大量股票数据，则可能需要用到批量多连接。 只支持windows系统，32 位的 Python 2.7 / Python 3.6.x 问题：\n需要自行维护停牌/退市股票列表，否则查询股票时服务器会自动返回600839的行情信息 分笔数据间隔3s，建议更小的时间间隔获取数据，否则最多可能出现3s延迟 不支持使用同一 Level 2 行情账户同时从多点连接，如果的确需要，您需要购买多个 Level 2 账户。 普通的五档实时行情、扩展行情没有任何 IP 限制，可以多点登录连接 ","date":"2017-11-06T09:29:00Z","permalink":"https://eryk-github-io.pages.dev/2017/11/06/tradex%E7%AC%94%E8%AE%B0/","title":"Tradex笔记"},{"content":"手续费 包括期货交易所和期货公司收取，期货公司手续费是交易所基础上的1.1 ～ 1.5 倍\n书籍推荐 道：斯坦利·克罗的《期货交易策略》和江恩的《如何从商品期货交易中获利》 术：中国期货业协会编的《铁矿石期货》，我们必须要了解铁矿石供给来源、中国铁矿石的进口量、铁矿石需求情况、铁矿石现货有哪些关键指标 关于大周期和小周期趋势问题 把握好小周期，积少成多\n期货定义 期货合约指由期货交易所统一制订的、规定在将来某一特定的时间和地点交割一定数量和质量实物商品或金融商品的标准化合约。\n期货交易所 商品期货交易所：大连商品期货交易所、郑州商品期货交易所、上海期货交易所 金融期货交易所：中国金融期货交易所 仓单 交易平台 文华财经、随身行（手机版）\n期货结算 涨跌停板 不同品种幅度不同，不同保证金会放大涨跌停，比如10倍杠杆，涨幅5%，对应本金则涨幅50%\n持仓限额 ","date":"2017-11-06T09:29:00Z","permalink":"https://eryk-github-io.pages.dev/2017/11/06/%E6%9C%9F%E8%B4%A7%E5%88%86%E6%9E%90%E4%B8%8E%E4%BA%A4%E6%98%93%E5%85%A5%E9%97%A8-live-%E7%AC%94%E8%AE%B0/","title":"期货分析与交易入门 live 笔记"},{"content":" 1 2 3 4 5 6 7 cd $1 python3 -O -m compileall . find . -name \u0026#39;*.pyc\u0026#39; -exec rename \u0026#39;s/.cpython-36.opt-1//\u0026#39; {} \\; find . -name \u0026#39;*.pyc\u0026#39; -execdir mv {} .. \\; find . -name \u0026#39;*.py\u0026#39; -type f -print -exec rm {} \\; find . -name \u0026#39;__pycache__\u0026#39; -exec rmdir {} \\; zip -r ../$1.zip ./* 转自：https://my.oschina.net/bfbd/blog/864310\n","date":"2017-10-27T12:18:00Z","permalink":"https://eryk-github-io.pages.dev/2017/10/27/python%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85pyc%E8%84%9A%E6%9C%AC/","title":"python编译打包pyc脚本"},{"content":"执行启动命令如下：\n1 nohup jupyter-notebook --ip=127.0.0.1 --port=8801 --notebook-dir=/home/eryk/jupyter_home \u0026amp; 错误信息如下：\n1 PermissionError: [Errno 13] Permission denied: \u0026#39;/run/user/1000/jupyter\u0026#39; 解决办法：\n1 unset XDG_RUNTIME_DIR 参考： https://github.com/jupyter/notebook/issues/1318\n","date":"2017-10-23T10:32:00Z","permalink":"https://eryk-github-io.pages.dev/2017/10/23/jupyter-notebook%E5%90%AF%E5%8A%A8%E6%8A%A5%E9%94%99/","title":"jupyter-notebook启动报错"},{"content":"系统日志显示\n1 2 3 4 5 6 7 8 9 10 11 Sep 22 12:40:44 gpu01 systemd[1]: Stopping User Manager for UID 1001... Sep 22 12:40:44 gpu01 systemd[1453]: Stopped target Default. Sep 22 12:40:44 gpu01 systemd[1453]: Stopped target Basic System. Sep 22 12:40:44 gpu01 systemd[1453]: Stopped target Timers. Sep 22 12:40:44 gpu01 systemd[1453]: Stopped target Sockets. Sep 22 12:40:44 gpu01 systemd[1453]: Stopped target Paths. Sep 22 12:40:44 gpu01 systemd[1453]: Reached target Shutdown. Sep 22 12:40:44 gpu01 systemd[1453]: Starting Exit the Session... Sep 22 12:40:44 gpu01 systemd[1453]: Received SIGRTMIN+24 from PID 28725 (kill). Sep 22 12:40:44 gpu01 systemd[1]: Stopped User Manager for UID 1001. Sep 22 12:40:44 gpu01 systemd[1]: Removed slice User Slice of xxx. google到如下解释： https://serverfault.com/questions/774491/what-is-sigrtmin24-in-syslog\n当用户session都退出之后，之前后台执行的进程就会被kill掉\n所以程序运行最好用nohup xxx \u0026amp;\n这还有一篇文章介绍nohup 和 \u0026amp; 的区别，核心意思是说：\n用nohup运行命令可以使命令永久的执行下去，和用户终端没有关系，例如我们断开SSH连接都不会影响他的运行，注意了nohup没有后台运行的意思；\u0026amp;才是后台运行\n\u0026amp;是指在后台运行，但当用户推出(挂起)的时候，命令自动也跟着退出\nhttp://blog.csdn.net/zhang_red/article/details/52789691\n","date":"2017-09-22T15:16:00Z","permalink":"https://eryk-github-io.pages.dev/2017/09/22/linux%E7%94%A8%E6%88%B7%E8%BF%9B%E7%A8%8B%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B%E8%A2%AB%E7%B3%BB%E7%BB%9Fkill%E6%8E%89%E4%BA%86/","title":"linux用户进程执行过程被系统kill掉了"},{"content":"CTA(Commodity Trading Advisors)商品交易顾问，通常也被称作管理期货基金，是由于其最初主要活跃于商品市场。CTA基金起源于1949年，随着期货交易品种的不断扩展，CTA基金在资产的风险管理与运作方面显得日趋重要，很多机构投资者诸如养老金、信托基金等都开始大量采用CTA作为他们投资组合中的重要组成部分，并在优化组合、分散风险等方面取得了良好的效果。\n研究对象 狭义：期货 广义：大宗商品期货，国债期货（利率期货），股票，外汇（包括spots和futures） 研究周期 分钟、小时和日线，少量tick\n研究方法 量价指标总结规律\n特点 低相关性 CTA策略投资于期货市场，和市场上大多数基础资产的相关性低\n高收益（回撤可控） 非线性（横盘期=加仓期） 除去低相关、高收益（回撤可控）之外，量化CTA基金还有一个显著的特性就是收益非线性。CTA基金的收益方式体现在低胜率、高盈亏比上，即一年的2-3波行情就能将全年的收益实现，其他时间是处于横盘或者回撤的状态。\nCTA分类 传统的CTA策略都是趋势追随策略\n广义上来说，CTA策略应该是趋势追踪策略为主，反转策略为辅\nCTA基金分类 公募期货基金(Public Funds) 私募期货基金(Private Pools) 个人管理期货账户 参考 什么是CTA策略？ https://zhuanlan.zhihu.com/p/20494478\n如何理解CTA交易策略? https://www.zhihu.com/question/38663897\n量化CTA策略背后的逻辑？ https://www.zhihu.com/question/36960610?sort=created\nCTA Fund https://baike.baidu.com/item/CTA%20Fund/1785877\n","date":"2017-09-21T09:27:00Z","permalink":"https://eryk-github-io.pages.dev/2017/09/21/cta%E7%AD%96%E7%95%A5commodity-trading-advisor-strategy/","title":"CTA策略(Commodity Trading Advisor Strategy)"},{"content":"什么是ETF套利 ETF套利，是指投资者可以在一级市场通过指定的ETF交易商向基金管理公司用一篮子股票组合申购ETF份额或把ETF份额赎回成一篮子股票组合，同时又可以在二级市场上以市场价格买卖ETF。\n假设在某个时段中，某只ETF成分股暴跌，使得该ETF的净值迅速走低，但该ETF的市场价格未能及时跟上，两者短暂地出现了一个价差，这时就可以选择买入ETF一篮子股票组合申购成ETF(以净值计价)，然后将ETF在二级市场上出售(以市场价格计价)，从而实现低买高卖，获取价差。\nETF套利的原理 一切要从ETF套利交易开始说起。这项交易模式在国内券商中比较普遍，甚至大型的私募基金也在做这种交易。\nETF套利交易原理通俗地说，就是一价原则，同一件产品在不同的市场有不同的价格，通过利用这些价差来获得盈利。比如上证50ETF对应的是上证50指数(1594.903, -6.48, -0.40%)成份股所组成的一揽子股票组合，组合中各只成份股权重不同，而不同的权重造成了一个兑换比例，投资者可以通过这种比例获得ETF份额，同时这些ETF份额也可以像股票一样在二级市场上交易。\n于是ETF套利就有两种交易顺序，一种是从股票二级市场购入一揽子股票，按照一定比例兑换成ETF份额，然后在ETF二级市场上卖出份额，这样的前提是一揽子股票价格比ETF价格低，所谓溢价；另一种则刚好相反，从ETF二级市场买入份额，按照一定比例兑换成一揽子股票，再拿到股票二级市场卖出，这样的前提是ETF价格低于一揽子股票价格，所谓折价。\n以光大证券操作ETF套利为例，8月16日上午，套利交易指令已经成交了72.7亿元股票，这说明光大证券正在进行溢价套利，希望用一揽子股票组合兑换ETF份额，并卖出ETF份额。\n该公司公告称，捅娄子的策略投资部在当天卖出了18.5亿元的50ETF、180ETF，如此计算尚有近54亿元的误操作股票没有处理，按照上述套利原则，这有可能是当日的溢价套利空间已经消失。\nETF套利四大技巧 交易型开放式指数基金（ETF）综合了开放式和封闭式基金的优点，既可向基金公司申购或赎回基金份额，又可像封闭式基金一样在二级市场按照市价进行买卖。由于跨市场间交易形式和交易机制的不同，基金一级市场份额净值和二级市场买卖价格间会存在价差的情况，这样套利空间应运而生。\n瞬间套利 ETF基本的套利交易主要有两种。一是折价套利，当ETF基金份额二级市场价格小于基金份额净值时，可通过二级市场买入ETF，之后在一级市场赎回一篮子股票，卖出股票组合获取现金。另外一种是溢价套利，和折价套利的方向相反，当ETF二级市场价格超过份额净值时，可买入股票组合，一级市场申购基金份额，之后在二级市场卖出获取现金。这两种就是ETF最常规的套利模式——瞬间套利。需要注意的是由于ETF申购赎回都有最小规模限制，例如100万份，瞬间套利并不适合中小投资者操作。\n延时套利 作为瞬间套利的延伸，ETF套利可以采取延时套利模式，也就是说投资者“非同步”地买卖ETF和一篮子股票，完成一圈完整交易的时间较长，这类套利其实更像是T+0交易。\n充分利用ETF交易规则，在相对低点，申购或买入ETF，在相对高点，再将ETF卖出或赎回。和瞬间套利相比，这类套利能否成功更看重指数短期的走势，风险更大。在实际操作中，为了确保收益的稳定性，减少风险，一般是当天完成一个交易轮回。\n事件套利 第三类ETF套利是事件套利。当ETF标的指数成分股停牌或涨跌停时，可利用ETF进行事件套利，套取看涨的股票或者减持看空的股票。事件套利的收益取决于停牌成分股的个体因素，具体包括两种模式。如果预计成分股在复牌后大幅度上涨，折价套利具体操作是在二级市场买入ETF，在一级市场进行赎回，得到一篮子股票组合，留下停牌股票，卖出其他股票。 例如，2008年10月9日长安汽车停牌，2009年2月16日复牌，期间深100指数涨幅32%，汽车板块因国家政策鼓励涨幅更甚，预计长安汽车开盘后会涨停复牌，投资者二级市场成功买入可能性较低。可通过赎回深100ETF，按停牌前价格3.67元获得长安汽车股票，复牌后该股有7个涨停板。如果预估成分股在复牌后会大幅度下跌，溢价套利具体操作是在二级市场上买入其他成分股组合和利用“允许现金替代”的标志，用现金来替代停牌股票，然后在一级市场申购ETF，然后在二级市场上卖出ETF。2008年的“长电事件”是这种套利的典型案例，当年5月8日，长江电力因整体上市开始停牌，此后沪深股市大幅下挫，上证指数跌幅近50%，为了降低损失，将长电套现，可先从二级市场市价买入上证50ETF其他49只股票，之后一级市场申购上证50ETF份额，再在二级市场卖出上证50ETF，顺利将长江电力出货。\n期现套利 股指期货和融资融券的推出，为做空A股市场提供了较好的工具。沪深指数期货是国内A股市场第一只也是唯一一只指数期货品种。沪深300指数包含的成分股多达300只，采用完全复制法难道较大，ETF根据标的指数，且能在二级市场交易，是期现套利中较好的现货工具。由于技术上的原因，国内目前还没有直接标的沪深300指数的ETF，多数进行期现套利的投资者采用的是“75%上证180ETF+25%深证100ETF”复合指数ETF作为现货替代品。\n自从2010年4月16日股指期货上市以来，上证180ETF和深100ETF二级市场成交量大幅激增。例如，股指期货上市初期，期货相对现货存在着一定的溢价，所谓的套利基本都是买入ETF，卖出股指期货合约，而在期现价差消除后，套利平仓盘卖出ETF，买入股指期货合约。　ETF套利与衍生品 A股首只股票指数期货品种沪深300期货自推出以来，成交活跃，已成为期货市场的主力品种之一。理论上来讲，剔除时间价值后，期货应与现货具有完全相同的走势。但事实上，由于期货投资者与现货投资者大多情况下分属两个投资群体，其对市场事件会有不同程度的解读，从而造成期货价格与现货价格的偏离。\n一旦价格偏离幅度大于套利成本，则套利投资者可以通过买入低估品种，同时卖出高估品种锁定价差。具体而言，当期货价格高于现货时，投资者可以通过买入沪深300ETF，卖出期货合约，锁定溢价，也就是我们常说的正向套利；相反，当期货价格低于现货时，投资者则可以通过买入期货，卖出沪深300ETF的方式获得反向套利折价。\n","date":"2017-09-06T17:31:00Z","permalink":"https://eryk-github-io.pages.dev/2017/09/06/etf%E5%A5%97%E5%88%A9etfs-arbitrage/","title":"ETF套利(ETF’s Arbitrage)"},{"content":"概念 证券公司PB业务（Prime Broker），即主经纪商业务，也称为主券商业务或大宗经纪业务，是指证券公司向专业机构投资者和高净值客户等提供集中托管清算、后台运营、研究支持、杠杆融资、证券拆借、资金募集等一站式综合金融服务。\n模式 相关文档 券商PB业务历史演进及对私募基金的影响浅析 https://wenku.baidu.com/view/c9a4952ae45c3b3566ec8b2e.html\nPB业务整体情况介绍及相关建议 https://wenku.baidu.com/view/ae353b446529647d26285208.html\nPB系统介绍 https://wenku.baidu.com/view/d55488ca376baf1ffd4fad8f.html\n我国证券公司发展PB业务现状及建议 https://wenku.baidu.com/view/a794f2475022aaea998f0fba.html\nhttps://www.zhihu.com/question/41086914/answer/98165214\n","date":"2017-08-28T10:00:00Z","permalink":"https://eryk-github-io.pages.dev/2017/08/28/pb%E7%B3%BB%E7%BB%9F%E4%BB%8B%E7%BB%8D/","title":"PB系统介绍"},{"content":"Level 1 Market Data Basic market data is known as level 1 market data, and includes the following information:\nBid price: The highest price that a trader is willing to buy an asset at. Bid size: The number of shares, forex lots or contracts that are available at the bid price. Ask price: The lowest price that a trader is willing to sell an asset at. Ask size: The number of shares, forex lots or contracts that are available at the ask price. Last price: The price at which the most recent trade was completed. Last size: The number of shares, forex lots or contracts that were traded in the most recent trade. Level 1 market data provides all of the information needed to trade using most trading systems. If you are trading a price action or indicator based strategy, then Level 1 market data should satisfy your informational needs.\nScalpers, and traders who trade based on changes in how other traders are bidding and offering (offer and ask are used interchangeably), will need Level 2 market data, which provides multiple levels of bids and offers.\nLevel 2 Market Data Additional market data is known as level 2 market data, the order book, or the depth of market, and includes the following additional information:\nHighest bid prices: The highest 5 to 15 prices (depending upon the market) where traders are willing to buy an asset. This means you not only see the current bid, but also all the bids currently below it. In actively traded stocks, there will typically be bids every $0.01 below the current bid, and in actively traded futures, there will typically be a bid each tick below the current bid. If there is a gap between the current bid and next bid, that typically means the stock or contract may experience a larger bid/ask spread and less volume.\nBid sizes: The number of shares, forex lots or contracts that are available at each of the bid prices.\nLowest ask prices: The lowest 5 to 15 prices (depending upon the market) where traders are willing to sell an asset. This means you not only see the current ask, but also all the asks above the current ask. In actively traded stocks, there will typically be asks every $0.01 above the current ask, and in actively traded futures, there will typically be an ask each tick above the current ask. If there is a gap between the current ask and next ask, that typically means the stock or contract may experience a larger bid/ask spread and less volume.\nAsk sizes: The number of shares, forex lots or contracts that are available at each of the ask prices.\nLevel 2 market data provides the additional information that is needed to trade based on changes that occur in the bids and offers. Level 2 market data is also known as the order book, because it shows the orders that are currently pending for the market. It is also known as the depth of market, or market depth, because it shows the number of contracts (or shares or lots) that are available at each of the bid and ask prices.\nOrder Book An order book is the list of orders (manual or electronic) that a trading venue (in particular stock exchanges) uses to record the interest of buyers and sellers in a particular financial instrument. A matching engine uses the book to determine which orders can be fulfilled i.e. what trades can be made. \u0026ndash;wikipedia\nLevel2行情 买卖行情 买入委托和卖出委托前10档的委托价和委托量,投资者可以看得更远,哪个价位有阻力？哪个价位有支撑？哪个价位有大笔挂单,一目了然。\n总买总卖 当前全部买入(卖出)委托的总量和加权均价,据此投资者可以判断盘中的支撑位(委买均价)、阻力位(委卖均价)、支撑力度(委买总量)、阻力大小(委卖总量),还可以根据这些数据的动态变化分析多空双方力量的变化,寻找行情的转折点\n成交明细 在Level-2之前,沪深交易所提供的都是行情快照,大家看到的分笔成交其实是两次快照期间累计的成交量和最后一笔的价格,而逐笔成交则是真实的每笔成交价和成交量的明细数据。逐笔成交极大地提高了行情的透明度。\n买卖队列 买一或卖一的前50笔委托单明细,根据委托单的大小或委托单是否有规律,可以判断委托是机构、大户、或散户所为。\n逐笔数据与分笔数据的根本区别 国内的Tick数据指的是 按固定时间间隔取个快照记录下来\n逐笔成交一般显示的数据格式为在几分几秒以多少价格分几笔成交了多少手。在这里我们要注意的是成交手数有时候是带小数点的，这是因为股票买进的股数最少是100股，委托的股数也应是100的整数倍，卖出却没有限制，因此成交的手数会有小数点。另外一点就是如果在成交价格和手数前面没有显示，则一半是默认的1笔。 分时成交一般显示的数据格式为在几分几秒以多少价格成交了多少手。这里需要注意的是成交手数永远是整数，不会出现小数点数字。其中现手累计数就是总手数。总手数也叫做成交量。有些软件在现量后面标注蓝色S和红色B，前者代表卖，后者代表买。目前市面上出现了LEVEL-2行情数据，比较具有代表性的是大智慧，在那里把分笔成交是叫分时成交，实际上就是我们在普通分析软件上F1看到的“分笔成交明细”，但是他和LEVEL-2行情数据提供的逐笔成交明细是不一样的。 分笔数据由于是合成混合数据，它是以最后1笔的买卖方向来表示该时间内（3秒或者6秒）的买卖方向，所以误差很大。（见下图说明） 一个孤独的数字是缺乏意义的，但是一些连续的数字则是充满想像的。一般来说，成交笔数越少，金额越大，表示成交比较强势，反之是弱势。尤其是成交手数比较大而集中的时候，表示有大资金活跃迹象，该股出现价格异动的概率就大，应该引起投资者的注意。而如果半天也没人买或者都是一些小单子在交易，则至少短期不大可能成为好股。 交易数据三要素\u0026mdash;-成交量、成交价格和成交笔数。不陌生的是前面两个，笔数就是交易批次。在成交量一定的前提下，笔数少说明交易力度强，反之就弱。笔数的变动与数量方向一致，交易为常态，反之就是非常态。 引用 https://www.thebalance.com/order-book-level-2-market-data-and-depth-of-market-1031118\nhttps://baike.baidu.com/item/Level-2\nhttps://www.zhihu.com/question/26950456\nhttp://www.cnblogs.com/chuncn/archive/2009/03/13/1410144.html\n","date":"2017-08-24T16:36:21Z","permalink":"https://eryk-github-io.pages.dev/2017/08/24/leve1level2-%E8%A7%A3%E9%87%8A/","title":"leve1、level2 解释"},{"content":"迅投交易终端——股票期货一体交易\n迅投交易终端是一款集股票交易、期货交易、组合交易为一体的智能化金融交易工具软件。其开放式的策略接口、智能算法交易、组合交易管理、多账户管理、高度自定义交易界面、完整数据导入导出功能，为大资金客户、机构客户和自动化交易客户提供了一支虚拟交易团队，高效、精准、优秀地完成每一个任务指令，为用户做多品种交易、大资金分批建仓、对冲套利交易提供极大的便利性，是投资者最强大的交易助手。\n策略接口： √ 开放的策略交易接口，无缝对接多种研发平台； √ 迅投解决交易周边问题，复杂策略高效执行； √ 策略与交易安全隔离，核心策略安全有保障。\n智能算法交易： √ 一键智能下单，软件自动下单、撤单、追单，减少人为操作失误； √ 支持多种算法交易策略，有效控制冲击成本、减少交易滑点； √ 各种策略参数在交易界面灵活设置，方便调用； √ 自动化执行与人工监控相结合，交易任务高效有序完成。\n组合交易管理： √ 完美股票组合导入导出，支持多篮子股票并行操作； √ 配合高效算法交易模块，一键轻松实现一篮子股票的批量交易，自动下单、撤单、追单； √ 支持多种策略快速下达组合交易任务； √ 支持预设多种手动补单策略； √ 篮子交易任务过程动态可视、人为可控。\n多账户管理： √ 多账户统一管理，实现多个账户的登录、委托、撤单、查询等功能； √ 分组管理、分组交易、批量下单； √ 支持多种交易任务分配方式； √ 支持跨公司账户交易管理。\n高度自定义交易界面： √ 所有模块随意拖拽、组合、定制，打造独一无二的自定义交易界面； √ 支持下单面板快捷复制，多品种交易尽在掌握； √ 单面板一键快捷下单，前所未有的轻松交易体验。\n完整数据导入导出： √ 支持多种格式的交易、分析数据导入导出，为投资者的交易分析、交易策略实现提供最大的便利性。\n原文地址: http://www.thinktrader.net/product/index.html\n","date":"2017-08-24T16:36:21Z","permalink":"https://eryk-github-io.pages.dev/2017/08/24/%E8%BF%85%E6%8A%95%E4%BA%A4%E6%98%93%E7%BB%88%E7%AB%AF/","title":"迅投交易终端"},{"content":"启动jupyter遇到的问题 ``` Exception in thread \u0026quot;main\u0026quot; java.lang.NoSuchMethodError: scala.collection.immutable.HashSet$.empty()Lscala/collection/immutable/HashSet; ``` 原因是因为spark依赖的scala版本与系统的不匹配，我的系统环境中scala版本是2.11.11，spark2.2.0目录下jars的scala版本是2.11.8 ","date":"2017-08-23T14:24:21Z","permalink":"https://eryk-github-io.pages.dev/2017/08/23/jupyter%E4%BD%BF%E7%94%A8pyspark%E6%95%99%E7%A8%8B/","title":"jupyter使用pyspark教程"},{"content":"Anaconda 是一个用于科学计算的 Python 发行版，支持 Linux, Mac, Windows, 包含了众多流行的科学计算、数据分析的 Python 包。\nAnaconda 安装包可以到 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 下载。\nTUNA 还提供了 Anaconda 仓库的镜像，运行以下命令:\n1 2 3 4 5 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/ conda config --set show_channel_urls yes 说明：\nconda-forge:\nA community led collection of recipes, build infrastructure and distributions for the conda package manager.\n","date":"2017-08-19T15:42:36Z","permalink":"https://eryk-github-io.pages.dev/2017/08/19/anaconda%E6%B7%BB%E5%8A%A0%E7%AC%AC%E4%B8%89%E6%96%B9%E6%BA%90/","title":"anaconda添加第三方源"},{"content":"搭建github博客，参考如下步骤 https://pages.github.com/ 注册域名，修改域名DNS地址 找个域名服务商注册个域名，我使用的是godaddy，如果以后需要指向国内空间，建议在国内域名服务商注册。\n注册好域名后，可以直接将域名cname到github博客地址，也可以使用dnspod.com的dns解析域名，在域名管理中把dns地址修改dnspod的dns：\n1 2 3 a.dnspod.com b.dnspod.com c.dnspod.com 然后需要在github上做个设置，把域名绑定到github账号上，否则直接访问域名会报404，具体设置步骤如下：\nhttps://help.github.com/articles/adding-or-removing-a-custom-domain-for-your-github-pages-site/\n使用hexo管理博客 Hexo是一个简单、快速、强大的基于 Github Pages 的博客发布工具，支持Markdown格式，有众多优秀插件和主题。\nhexo安装步骤参考：\nhttps://hexo.io/\n推荐next博客主题，我的博客就是使用的这个主题，地址是：\nhttps://github.com/iissnan/hexo-theme-next\n设置_config.yml和github sshkey 1 2 3 4 deploy: type: git repo: https://github.com/YourgithubName/YourgithubName.github.io.git branch: master hexo发布时会把更新提交到仓库，所以需要设置github sshkey\n发布文章 基本命令如下：\n进入blog目录下，执行如下命令创建一篇博客\n1 hexo new post 文章标题 创建好后可以在markdown工具中编写文章，macbook下推荐用MWeb来写博客，MWeb有两种模式：文档库和外部模式，使用外部模式到blog目录下就可以编写了\n编写好博客后发布：\n1 hexo d -g 等待几秒中后刷新博客地址就可以看到更新了。\n","date":"2017-08-18T10:16:44Z","permalink":"https://eryk-github-io.pages.dev/2017/08/18/10%E5%88%86%E9%92%9F%E6%90%AD%E5%BB%BAgithub%E5%8D%9A%E5%AE%A2/","title":"10分钟搭建github博客"},{"content":"基础概念 证券市场的交易机制\n分为报价驱动市场(Quote-driven Market 和订单驱动市场(Order-driven Market)两类，前者依赖做市商提供流动性，后者通过限价单订单提供流动性,交易通过投资者的买进委托和卖出委托竞价所形成。中国的证券市场属于订单驱动市场，包括股票市场和期货市场。\n金融市场微观结构理论\n是对金融市场上金融资产的交易机制及其价格形成过程和原因进行分析。一般认为该理论产生于1960年代末，德姆塞茨1968年发表的论文《交易成本》奠定了其基础。\n订单簿(order book)\n信息簿(MessageBook)\n包括最明细的订单撮合数据，包括每个订单的下单量、成交价、订单类型等信息\n对冲\n金融学上，对冲（hedge）指特意减低另一项投资的风险的投资。它是一种在减低商业风险的同时仍然能在投资中获利的手法。一般对冲是同时进行两笔行情相关、方向相反、数量相当、盈亏相抵的交易。行情相关是指影响两种商品价格行情的市场供求关系存在同一性，供求关系若发生变化，同时会影响两种商品的价格，且价格变化的方向大体一致。方向相反指两笔交易的买卖方向相反，这样无论价格向什么方向变化，总是一盈一亏。当然要做到盈亏相抵，两笔交易的数量大小须根据各自价格变动的幅度来确定，大体做到数量相当。\n期货 合约 指由期货交易所统一制订的、规定在将来某一特定的时间和地点交割一定数量和质量实物商品或金融商品的标准化合约。通常所说的期货就是指期货合约。\n主力合约 指的是成交量最大的合约。因为它是市场上最活跃的合约，所有投机者基本上都在参与这个合约。也有说法是主力合约是持仓量最大的合约，因为通常来讲，持仓量最大的合约也是成交量最大的合约。\nIF、IH、IC IF：（share price）Index Future，直译就是股指期货，标的物是沪深300指数。命名来自英文。 IH：I表示股指期货，H是“沪”的拼音第一个字母。标的物是上证50。命名中英混杂。 IC：I表示股指期货，C是China的第一个字母，标的物是中证500。命名更是不伦不类。\nOpen Interest 未平仓合约，持仓兴趣\n","date":"2017-08-18T09:02:57Z","permalink":"https://eryk-github-io.pages.dev/2017/08/18/%E9%87%91%E8%9E%8D%E5%90%8D%E8%AF%8D%E8%A7%A3%E9%87%8A%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0/","title":"金融名词解释（持续更新）"},{"content":"执行命令:\n1 pip install pymssql 报错信息如下：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Running setup.py install for pymssql ... error Complete output from command /home/lthpc/anaconda3/bin/python -u -c \u0026#34;import setuptools, tokenize;__file__=\u0026#39;/tmp/pip-build-cpwncwyq/pymssql/setup.py\u0026#39;;f=getattr(tokenize, \u0026#39;open\u0026#39;, open)(__file__);code=f.read().replace(\u0026#39;\\r\\n\u0026#39;, \u0026#39;\\n\u0026#39;);f.close();exec(compile(code, __file__, \u0026#39;exec\u0026#39;))\u0026#34; install --record /tmp/pip-4l_hdx9q-record/install-record.txt --single-version-externally-managed --compile: setup.py: platform.system() =\u0026gt; \u0026#39;Linux\u0026#39; setup.py: platform.architecture() =\u0026gt; (\u0026#39;64bit\u0026#39;, \u0026#39;ELF\u0026#39;) setup.py: platform.linux_distribution() =\u0026gt; (\u0026#39;debian\u0026#39;, \u0026#39;stretch/sid\u0026#39;, \u0026#39;\u0026#39;) setup.py: platform.libc_ver() =\u0026gt; (\u0026#39;glibc\u0026#39;, \u0026#39;2.2.5\u0026#39;) setup.py: Not using bundled FreeTDS setup.py: include_dirs = [\u0026#39;/usr/local/include\u0026#39;] setup.py: library_dirs = [\u0026#39;/usr/local/lib\u0026#39;] running install running build running build_ext cythoning _mssql.pyx to _mssql.c warning: _mssql.pyx:143:4: Exception already a builtin Cython type building \u0026#39;_mssql\u0026#39; extension creating build creating build/temp.linux-x86_64-3.6 gcc -pthread -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/usr/local/include -I/home/lthpc/anaconda3/include/python3.6m -c _mssql.c -o build/temp.linux-x86_64-3.6/_mssql.o -DMSDBLIB _mssql.c:435:22: fatal error: sqlfront.h: No such file or directory compilation terminated. error: command \u0026#39;gcc\u0026#39; failed with exit status 1 google得到以下解决办法：\nhttps://stackoverflow.com/questions/17368964/trying-to-install-pymssql-on-ubuntu-12-04-using-pip\n尝试执行命令安装FreeTDS依赖包：\nsudo apt-get install freetds-dev\n如果安装过程出现依赖包版本的问题请先更新ubuntu软件源\nsudo apt-get update\n再次执行pymssql，安装成功:\n1 2 3 4 5 6 7 8 9 $ pip install pymssql Collecting pymssql Using cached pymssql-2.1.3.tar.gz Building wheels for collected packages: pymssql Running setup.py bdist_wheel for pymssql ... done Stored in directory: /home/lthpc/.cache/pip/wheels/c1/1e/75/bc600eb8a5c9ed77fb1edf15ae5a48b5b427b0390c9a7c9dff Successfully built pymssql Installing collected packages: pymssql Successfully installed pymssql-2.1.3 ","date":"2017-08-17T16:15:54Z","permalink":"https://eryk-github-io.pages.dev/2017/08/17/python%E8%A3%85pymssql%E6%97%B6%E9%81%87%E5%88%B0error-command-gcc-failed-with-exit-status-1/","title":"python装pymssql时遇到error: command 'gcc' failed with exit status 1"},{"content":"docker启动Grafana + Influexdb 1 2 3 4 5 6 7 8 docker run -d \\ --name docker-statsd-influxdb-grafana \\ -p 3003:3003 \\ -p 8083:8083 \\ -p 8086:8086 \\ -p 22022:22 \\ -p 8125:8125/udp \\ samuelebistoletti/docker-statsd-influxdb-grafana:latest 设置InfluxDB 打开 http:localhost:8083，设置用户名密码\n1 2 3 Username: root Password: root Port: 8086 设置Grafana 打开http:localhost:3003，登录用户名密码为\n1 2 Username: root Password: root 登录之后按步骤设置数据源\n1 2 3 4 Url: http://localhost:8086 Database:\ttelegraf User: telegraf Password:\ttelegraf 安装并设置TeleGraf 下载地址：https://portal.influxdata.com/downloads\n设置 /etc/telegraf/telegraf.conf 修改influxdb地址，用户名及密码，设置hostname\n重启服务\nservice telegraf restart\n导入Grafana Dashboard 下载最新版本的dashboard配置： https://grafana.com/dashboards/1443/revisions\n在grafana的新建dashboard并导入配置，完成。\n注意 docker内部已经启动了telegraf，如果不需要的话可以停掉，在多台服务器上安装并配置Telegraf写入同一Influxdb就可以实现对集群进行系统监控。\n参考 使用 Grafana、collectd 和 InfluxDB 打造现代监控系统 docker-statsd-influxdb-grafana Send CollectD metrics to InfluxDB ","date":"2017-08-14T23:53:13Z","permalink":"https://eryk-github-io.pages.dev/2017/08/14/docker-grafana-influxdb-telegraf%E5%AE%89%E8%A3%85%E9%83%A8%E7%BD%B2/","title":"Docker+Grafana+Influxdb+Telegraf安装部署"},{"content":"jupyter notebook extensions 安装 pip方式安装 pip install jupyter_contrib_nbextensions\n或者通过github master branch安装\npip install https://github.com/ipython-contrib/jupyter_contrib_nbextensions/tarball/master\nConda方式安装 conda install -c conda-forge jupyter_contrib_nbextensions\n通过github 仓库安装 1 2 git clone https://github.com/ipython-contrib/jupyter_contrib_nbextensions.git pip install -e jupyter_contrib_nbextensions 常用插件列表 全部jupyter插件列表在这里：\nhttp://jupyter-contrib-nbextensions.readthedocs.io/en/latest/nbextensions.html\n我觉得有用的插件列表：\nAutopep8\n格式化代码插件\nCodefolding 和 Codefolding in Editor\n折叠代码插件\nCollapsible Headings\nCollapsible Headings icon Allows notebook to have collapsible sections, separated by headings\ncontrib_nbextensions_help_item：帮助\nDrag and Drop\nThis extension allows dragging\u0026amp;dropping images from the desktop or other programs into a notebook.\nExecuteTime：\nDisplay when each cell has been executed and how long it took\nFreeze\nFreeze cells (forbid editing and executing) or make them read-only\nhighlighter\nmarkdown内容高亮\nHinterland\n实时的自动补全，很不错\nNbextensions dashboard tab \u0026amp; Nbextensions edit menu item\nScrollDown\n自动向下滚动输出\nSnippets \u0026amp; Snippets Menu\n插入代码片段的，可以自定义\nTable of Contents (2)\nThe toc2 extension enables to collect all running headers and display them in a floating window, as a sidebar or with a navigation menu. The extension is also draggable, resizable, collapsable, dockable and features automatic numerotation with unique links ids, and an optional toc cell.\ntable_beautifier\nAdd bootstrap styling to tables in markdown cells and in html/md output\nToggle all line numbers\nAdd a toolbar button and hotkey to toggle all cells\u0026rsquo; line numbers on or off\nTree Filter\nAn extension that allows you to filter by filename in the Jupyter notebook file tree (aka dashboard) page.\nVariable Inspector\nThe Variable Inspector extension collects all defined variables and display them in a floating window.\n","date":"2017-08-13T16:25:19Z","permalink":"https://eryk-github-io.pages.dev/2017/08/13/%E6%88%91%E7%9A%84jupyter%E6%8F%92%E4%BB%B6%E5%88%97%E8%A1%A8/","title":"我的jupyter插件列表"},{"content":"原始数据样例如下：\n1 2 3 4 date code count 20170801 000001 10 20170802 000002 20 20170803 000001 30 使用pivot处理数据，命令如下：\ndf.pivot(index=\u0026lsquo;date\u0026rsquo;,columns=\u0026lsquo;code\u0026rsquo;,values=\u0026lsquo;count\u0026rsquo;)\n执行后报错信息：\nValueError: Index contains duplicate entries, cannot reshape\n说明column有重复信息，使用如下命令检查重复列内容：\n1 2 df = df.sort_values([\u0026#39;date\u0026#39;,\u0026#39;code\u0026#39;,\u0026#39;count\u0026#39;],ascending=[1,1,0]) df = df[(df[\u0026#39;code\u0026#39;] == df[\u0026#39;code\u0026#39;].shift(1)) | (df[\u0026#39;code\u0026#39;] == df[\u0026#39;code\u0026#39;].shift(-1))] 发现code列有哪些重复数据\n","date":"2017-08-10T16:54:53Z","permalink":"https://eryk-github-io.pages.dev/2017/08/10/pandas%E4%BD%BF%E7%94%A8pivot%E6%97%B6%E9%81%87%E5%88%B0index-contains-duplicate-entries-cannot-reshape/","title":"pandas使用pivot时遇到Index contains duplicate entries, cannot reshape"},{"content":"生成jupyter配置文件:\njupyter notebook \u0026ndash;generate-config\n注意：generate前是两个\u0026quot;-\u0026quot;，不知道为什么markdown里是两个，显示的时候成一个了\n生成好的配置文件位置在：\n~/.jupyter/jupyter_notebook_config.py\n生成自签名SSL证书：\ncd ~/.jupyter openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout notebook_cert.key -out notebook_cert.pem\n生成一个登录密码的hash:\npython -c \u0026ldquo;import IPython;print(IPython.lib.passwd())\u0026rdquo;\n修改jupyter_notebook_config.py配置文件中的如下选项：\n1 2 3 c.NotebookApp.certfile = u\u0026#39;/home/xxxx/.jupyter/notebook_cert.pem\u0026#39; c.NotebookApp.keyfile = u\u0026#39;/home/xxxx/.jupyter/notebook_cert.key\u0026#39; c.NotebookApp.password = u\u0026#39;sha1:991ec9cd2f39:522598e19891bab1ecaa3a9072e71f45811af9f2\u0026#39; 重启jupyter，使用浏览器访问：https://your_domain_or_IP:8080\n参考 http://jupyter-notebook.readthedocs.io/en/latest/public_server.html#notebook-server-security\nhttp://www.linuxdiyf.com/linux/22884.html\n","date":"2017-08-09T09:15:37Z","permalink":"https://eryk-github-io.pages.dev/2017/08/09/%E4%BD%BF%E7%94%A8https%E6%96%B9%E5%BC%8F%E8%BF%9E%E6%8E%A5jupyter/","title":"使用https方式连接jupyter"},{"content":"","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""},{"content":"","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""},{"content":"","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""},{"content":"","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""},{"content":"","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""},{"content":"","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""},{"content":"","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""},{"content":"","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""},{"content":"","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""},{"content":"title: FIX协议介绍与QuickFIX使用入门(上) date: 2019-07-16 16:06:00 categories: 量化交易系统 tags: [FIX]\n定义 FIX协议是由国际FIX协会组织提供的一个开放式协议，目的是推动国际贸易电子化的进程，在各类参与者之间，包括投资经理、经纪人，买方、卖方建立起实时的电子化通讯协议。\nFIX协议的目标是把各类证券金融业务需求流程格式化，使之成为一个个可用计算机语言描述的功能流程，并在每个业务功能接口上统一交换格式，方便各个功能模块的连接。\nFIX协议各个版本对股票、期权和期货的支持程度，目前市场上使用FIX4.4的较多。\nFIX通信模型 Initiator：发起者，建立通信连路，通过发送初始Logon消息发起会话的参与方。 Acceptor：接收方 FIX会话的接收方。负责执行第一层次的认证和通过传输Logon消息的确认正式声明连接请求被接受。 原则：先发起者为Initiator ，接受者为Acceptor 。 标准模式以网关为Acceptor，客户端为Initiator做为常用模式。 基本概念 FIX Connection FIX连接 由3部分组成：logon登录，message exchange消息传输，和logout注销.\nFIX Session FIX会话由一个或多个FIX Connection FIX连接组成。一个FIX会话可以有多次登录。一个FIX会话定义为一个在连接双方间的的带有连续序列号的有序消息双向传输流。 单个FIX会话能够跨越多个连续（不是并行的）的物理连接。在一个维持的，单独的FIX会话中，参与方能够多次连接和断开连接。连接的参与方必须根据单个系统及时间区域需求，公共协商会话的开始和结束。无论什么原因，重新设置接收和发送序列号为1，意味着一个新的FIX会话的开始。\n建议一个新的FIX会话在每24小时期间建立一次。可以维持24小时的连接和通过设置在Logon消息中的ResetSeqNumFlag建立一套新的序列号。\nSequence Num 所有的FIX消息都由一个唯一的序列号进行标示。序列号在每一个FIX会话开始时被初始化为1，并在整个会话期间递增。监控序列号可以使会话参与者识别和处理丢失的消息，当在一个FIX会话中重新连接时能够优雅地进行应用程序同步。每个会话将建立一组互不依赖的接受和发送序列。会话参与者将维护一个赋予发送消息的序列和一个监控接受消息的消息块间隙序列号。\n心跳 Heartbeats 在消息交互期间，FIX应用程序将周期性产生Heartbeat心跳消息。该心跳消息可以监控通信链路状态及识别接受序列号间隙。发送Heartbeat的周期间隔由会话发起者使用在Logon消息中HeartBtInt域进行定义。Heartbeat心跳消息的时间间隔应当在每一个消息发送后复位，即发送一个消息后，在间隔给定的时间内无其它消息发送则发送一个Heartbeat心跳消息。HeartBtInt的值应当被会话双方认同，由会话发起方定义并由会话接收者通过Logon消息进行确认。同一个HeartBtInt被会话双方——登录的发起者和登录的接受者共同使用。\nOrdered Message Processing FIX协议假设消息在所有参与者间完全按照顺序进行传输。协议的实现者在设计消息间隙填充处理时应当考虑这个假设。有两种方式处理消息间隙。每一个都要求所有的消息时最后一个接收消息的后续消息或在维护一个所有新消息有序序列时，请求特定丢失消息。比如：接收方丢失了5个消息块中的第二个，程序能忽略第3到第5个消息，产生一个对消息2到消息5的重传请求，或者从消息2到无穷大消息编号的重传请求。另外的方式是暂时存储消息3到消息5，仅要求重传消息2。对于这两种方式，消息3到消息5都不应该先于消息2进行处理。\nPossible Duplicate 当一个FIX引擎对一个消息是否成功地被指定的目标接收或者当对一个重传请求进行响应时，将会产生一个可能的消息复制。这个消息将用同样的序列进行重新传送，此时在头部的PossDupFlag域将会被设置为‘Y’。接收端程序负责处理该重发消息，可以作为一个新消息进行处理，或者根据实际情况忽略该消息。所有重传请求的响应消息都将包含其值为‘Y’的PossDupFlag域。没有PossDupFlag域或者PossDupFlag域为‘N’的消息应被当作初始传送消息。注意，一个PossDupFlag值为‘Y’的重传消息需要重新计算其CheckSum值。一个可能的复制消息里发生变化的域包括：CheckSum，OrigSendingTime，SendingTime，BodyLength和PossDupFlag。加密相关域（SecureDataLen和SecureData）也必须被重新构造。\nPossible Resends 模糊的应用层消息可能随同PossResend标志被重传。当一个指令没有在规定时间长度内进行确认或者终端用户挂起该指令没有进行传送时这种方法非常有用。接收程序必须识别此标志，并质疑其内部域以确定该指令是否在之前已经被接收过。注意，可能的重传消息将包含与原始消息相同的数据体，但包含PossResend标志和一个新的序列号。此外，CheckSum和与加密相关的域值需要重构。\n数据完整校验 Data Integrity 消息数据内容的完整性可以参用两种方式来验证：消息长度和效验码检查。程序通过计算BodyLength域到（并包含）在CheckSum标记（“10=”）后的分界符的字符数与在BodyLength中标示的消息长度进行比较来完成完整性效验。ChekSum完整性检查，通过计算从域“8=”中“8”开始，包括紧跟在CheckSum标记域的分界符每个字符的2进制和同CheckSum进行比较得到。\n消息确认 Message Acknowledgements 消息数据内容的完整性可以参用两种方式来验证：消息长度和效验码检查。程序通过计算BodyLength域到（并包含）在CheckSum标记（“10=”）后的分界符的字符数与在BodyLength中标示的消息长度进行比较来完成完整性效验。ChekSum完整性检查，通过计算从域“8=”中“8”开始，包括紧跟在CheckSum标记域的分界符每个字符的2进制和同CheckSum进行比较得到。\n加密 Encryption 敏感数据在公众网络上的传输建议采用数据加密技术来掩饰应用消息。 加密算法由连接双方共同协商。 一个消息的任何一个域可以被加密并放在SecureData域中。然而，一些显示的标志域必须采用明文进行传输。为确保完整性，明文域可以在SecureData域中重复。 当使用加密时，建议但不是必须，所有的消息体都进行加密。如果一个消息中的重复组数据中的部分数据要加密，这个重复组必须全部进行加密。 预先协商好的加密算法在Logon消息中进行声明。\n自定义域 FIX为给用户提供最大的灵活性，FIX协议允许用户自定义域。这些域在认同的参与者之间实现、应用，并且应注意避免冲突。 Tag数在5000 到9999保留用于用户自定义域。这些tag值用于企业联盟的信息交换。可以通过FIX网站进行注册。 10000以上保留用于单一企业内部使用。不用注册。 消息类型 初始化过程之后，正常的消息交换将开始。所有有效的消息格式的细节将在“Adminitrative Message ”管理消息和“Application Messages”应用消息部分介绍。\n1. 管理信息 它是为了信息交换过程更加顺畅一致而使用的控制,包括:登录、心跳、检验请求、重新发送请求、拒绝(交换过程)顺序重设及注销等。\n2. 应用消息 也就是交易的数据,它包括:\n公告 宣布已完成的交易信息。 重要提示 告知由经纪人买卖的证券是由私人股份有限公司所有,还是由代理持有,以及持有量。 消息 是经纪人和机构之间传送的一般自由格式信息,带有识别信息紧急性和商号主题词分类标志。 电子邮件 其格式和用途与消息信息相同,但更倾向于双方非公开的用途。 报价请求 有些市场,要求经纪人在每次订单前提出报价。 报价与多宗报价 回应报价请求的信息,并用于发表主动的报价。 请求对多宗报价的确认 使用报价回应水平标记,有选择地支持对报价的确认。 报价撤销 报价发起人用于撤销报价。 报价状况请求 机构用来生成执行报告。 报价确认 针对报价、多宗报价、报价撤销和报价请求,作出回应。 行情数据请求 通过此请求得到所指定的证券和外汇交易报价的行情数据。 行情数据—快照/完全刷新 该信息用于发送双方的订单登记簿、报价清单、交易清单、指数值、开盘价、收盘价、成交单价、最高价、最低价和变动加权平均价等。 行情数据—添加刷新 用于添加刷新请求。 行情数据请求拒绝 用于经纪人因交易或技术上的原因不承兑行情数据请求的情况。 证券定义请求 用于某一指定证券与第二方交易。 证券定义 接受或拒绝证券定义信息中请求的证券,发回证券及类型清单。 证券状况请求 用于提出有关证券状况的请求。 证券状况 提供有关证券状况改变的报告。 交易盘状况请求 请求有关市面状况的信息。 交易盘状况 提供有关市场状况的信息。 新订单—单一 机构向经纪人提供有关证券或外汇的订单。 执行报告 确认收到订单或订单改变信息,传递订单状况或订单成交信息,报告交易的费用。 未知交易 通知交易方,收到的订单已被执行。 订单撤销/替换请求 改变订单的参数。 订单撤销拒绝 是经纪人在不能承兑所收到的撤销请求信息时发出的信息。 订单状况请求 机构要求经纪人生成并发挥有关订单状况的信息。 划拨 指定如何将一个订单或一组订单细分为一个或多个账户。 划拨确认 确认收到机构发送的划拨信息及状态。 结算指令 经纪人或机构交易结算的指令。 出价请求 在“非公开”市场与“公开”市场,因市场规则不同,该信息的用法也不同 出价回应 因两个市场规则不同,有不同的用法。 新订单—清单 因两种市场规则的不同而不同。 敲定价 交换本金交易的敲定价。 状况清单 卖方以主动方式发送回应状况清单请求信息。 清单执行 机构用于指示经纪人开始执行已被提交的证券订单信息。 清单撤销执请求 用于机构希望在执行交易盘之前或之中,撤销已被提交的证券订单消息。 状况清单请求 用于机构指示经纪人生成有关某一状况清单的信息。 清单订单信息的分解 使用与其它FIX信息相同的方法,支持程序交易中的信息分解。 交易信息拒绝 拒绝因遵循了交易盘规则而不能以其它方式进行拒绝的应用层面的信息。 消息格式 数据类型 整数int,浮点数float,单个字符char,布尔Boolean,字符串String,数据data\n每条FIX信息都是由一系列带有〈标记〉=〈值〉的域组成。每个标记代表不同的含义,可以是信息的类型,目标商务名称,证券买入价等。FIX协议规定了0～5000的标记含义（fix信息字典）,5000以上可由使用者自己定义,以适用特定的应用。\n参考 https://www.fix-events.com/Archives/asianfix2008/cn/pdf/AlanDean_Chi.pdf\nhttps://l297.oschina.io/15034517662312.html\nhttps://juejin.im/post/5bf7c4ae51882528c4467649\nhttps://www.huiyep.com/knowledge/155062.html\nhttps://github.com/quickfix/quickfix/blob/master/examples/executor/python/executor.py\n我的微信公众号：pyquant\n","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""},{"content":"title: Python调用C/C++入门 date: 2019-08-23 14:19:00 categories: 量化交易系统 tags: [ctypes]\n1. 背景 最近公司在某券商募集了一笔资金，需要对接其提供的程序化接口方便以后进行交易，对方只提供了c++版本程序，我们系统是python开发的，所以需要用python调用c++，大致了解下了python调用c++的几种方式，下面根据网上的资料介绍下几种方式优缺点，最后给个mac环境下python调用c++的例子。\n2. Python调用C/C++程序方法 ctypes\n如果是 C 函数库，则直接 load 这个库，然后调用即可； 如果是 C++ 函数库，则需要用extern关键字封装一个供 C 使用的函数，即把类隐藏到一些 C 风格的函数里，然后用 extern 标明这些函数，以方便外部调用。 SWIG\nSWIG完整支持ANSI C，支持除嵌套类外的所有C++特性。SWIG是一个接口编译器，旨在为C/C++方便地提供脚本语言接口。SWIG不仅可以为C/C++程序生成 Python接口，目前可以生成CLISP,Java,Lua,PHP,Ruby,Tcl等19种语言的接口。SWIG被Subversion, wxPython, Xapian等项目使用。值得一提的是，Google也使用SWIG。\nSIP\nSIP是一种Python工具，用于自动生成Python与C、C++库的绑定。SIP最初是在1998年用PyQt开发的，用于Python与Qt GUI toolkit的绑定，但适用于生成任何C或C++库的绑定。\nCython\nCython是让Python脚本支持C语言扩展的编译器，Cython能够将Python+C混合编码的.pyx脚本转换为C代码，主要用于优化Python脚本性能或Python调用C函数库。由于Python固有的性能差的问题，用C扩展Python成为提高Python性能常用方法，Cython算是较为常见的一种扩展方式。\nBoost.Python\nBoost.Python是Boost提供的一个C++的模板库，用以支持Python和C++的无缝互操作。相对SWIG来说，这个库的优势是功能通过C++ API完成，不用学习写新的接口文件。对C++的支持更自然、完整。\nctypes SWIG SIP Cython Boost.Python 是否支持Python3 支持 支持 支持 支持 支持 对接难易程度 简单 中等 中等 困难 困难 是否需开发封装代码 c++需要,c不需要 需要 需要 需要 需要 3. 使用ctypes调用C/C++ 例子 3.1 安装 GNU 的 C/C++ 编译器 UNIX/Linux: http://gcc.gnu.org/install/\nMac OS X: 安装 Xcode就能使用编译器\nWindows: www.mingw.org\n以mac为例，安装之后命令行输入 g++ -v 查看是否安装成功\n1 2 3 4 5 6 ~/ g++ -v Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1 Apple LLVM version 10.0.0 (clang-1000.11.45.5) Target: x86_64-apple-darwin18.2.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin 3.2 开发c++例子程序:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include \u0026lt;iostream\u0026gt; class Test{ public: void print(){ std::cout \u0026lt;\u0026lt; \u0026#34;Hello world!\u0026#34; \u0026lt;\u0026lt; std::endl; } }; extern \u0026#34;C\u0026#34; { Test* Test_new(){ return new Test(); } void Test_print(Test* test){ test-\u0026gt;print(); } } 保存文件未test.cpp，编译代码生成动态链接库:\n1 g++ -o test.so -shared -fPIC test.cpp 执行完成后会在当前目录下生辰test.so 文件\n3.3 Python中调用so\n1 2 3 4 5 6 7 8 9 10 11 12 from ctypes import cdll lib = cdll.LoadLibrary(\u0026#39;./test.so\u0026#39;) class Test(object): def __init__(self): self.obj = lib.Test_new() def print(self): lib.Test_print(self.obj) test = Test() test.print() 执行Python代码会输出 Hello world!，说明执行成功\n参考 https://stackoverflow.com/questions/145270/calling-c-c-from-python\n关于python对接c/c++各种方案的优缺点，这篇文章说的比较清楚: https://www.jb51.net/article/63623.htm\n我的微信公众号：pyquant\n","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""},{"content":"","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""},{"content":"","date":"0001-01-01T00:00:00Z","permalink":"https://eryk-github-io.pages.dev/1/01/01/","title":""}]