[
  {
    "path": ".gitignore",
    "content": ".DS_Store"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Current file\",\n            \"type\": \"debugpy\",\n            \"request\": \"launch\",\n            \"program\": \"${file}\",\n            \"args\": [],\n            \"console\": \"integratedTerminal\",\n            \"python\": \"${env:HOME}/miniconda3/bin/python\",\n            \"justMyCode\": false\n        }\n    ]\n}"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"editor.formatOnSave\": true,\n    \"python.defaultInterpreterPath\": \"${env:HOME}/miniconda3/bin/python\",\n}"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n  <img src=\"static/images/awesome-systematic-trading.jpeg\" height=200 alt=\"\"/>\n  <h1>Awesome Systematic Trading</h1>\n</div>\n<div align=center><img src=\"https://awesome.re/badge.svg\" /></div>\n\n[希望阅读中文版？点我](./README_zh.md)\n\nWe are collecting a list of resources papers, softwares, books, articles for finding, developing, and running systematic trading (quantitative trading) strategies.\n\n<!-- omit in toc -->\n### What will you find here?\n\n- [97 libraries and packages](#libraries-and-packages) for research and live trading\n- [40+ strategies](#strategies) described by institutionals and academics\n- [55 books](#books) for beginners and professionals\n- [23 videos](#videos) and interviews\n- And also some [blogs](#blogs) and [courses](#courses)\n\n<div align=\"center\" style=\"margin-bottom: 50px; margin-top: 50px;\">\n  <div style=\"border: 2px solid #007bff; border-radius: 10px; padding: 20px; margin-bottom: 20px;\">\n    <h2>📈 Interested in trading strategies implemented in Python?</h2>\n    <p>Visit our comprehensive collection at <a href=\"https://paperswithbacktest.com\" target=\"_blank\">paperswithbacktest.com</a> for exclusive content!</p>\n  </div>\n</div>\n\n\n<details>\n<summary>Click here to see the full table of content</summary>\n\n- [Libraries and packages](#libraries-and-packages)\n  - [Backtesting and Live Trading](#backtesting-and-live-trading)\n    - [General - Event Driven Frameworks](#general---event-driven-frameworks)\n    - [General - Vector Based Frameworks](#general---vector-based-frameworks)\n    - [Cryptocurrencies](#cryptocurrencies)\n  - [Trading bots](#trading-bots)\n  - [Analytics](#analytics)\n    - [Indicators](#indicators)\n    - [Metrics computation](#metrics-computation)\n    - [Optimization](#optimization)\n    - [Pricing](#pricing)\n    - [Risk](#risk)\n  - [Broker APIs](#broker-apis)\n  - [Data Sources](#data-sources)\n    - [General](#general)\n    - [Cryptocurrencies](#cryptocurrencies-1)\n  - [Data Science](#data-science)\n  - [Databases](#databases)\n  - [Graph Computation](#graph-computation)\n  - [Machine Learning](#machine-learning)\n  - [TimeSeries Analysis](#timeseries-analysis)\n  - [Visualization](#visualization)\n- [Strategies](#strategies)\n  - [Bonds, commodities, currencies, equities](#bonds-commodities-currencies-equities)\n  - [Bonds, commodities, equities, REITs](#bonds-commodities-equities-reits)\n  - [Bonds, equities](#bonds-equities)\n  - [Bonds, equities, REITs](#bonds-equities-reits)\n  - [Commodities](#commodities)\n  - [Cryptos](#cryptos)\n  - [Currencies](#currencies)\n  - [Equities](#equities)\n- [Books](#books)\n  - [Beginner](#beginner)\n  - [Biography](#biography)\n  - [Coding](#coding)\n  - [Crypto](#crypto)\n  - [General](#general-1)\n  - [High Frequency Trading](#high-frequency-trading)\n  - [Machine Learning](#machine-learning-1)\n- [Videos](#videos)\n- [Blogs](#blogs)\n- [Courses](#courses)\n</details>\n\n<!-- omit in toc -->\n> ### How can I help?\n> You can help by submitting an issue with suggestions and by sharing on Twitter:\n>\n> [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=A%20free%20and%20comprehensive%20list%20of%20papers%2C%20libraries%2C%20books%2C%20blogs%2C%20tutorials%20for%20quantitative%20traders.&url=https://github.com/paperswithbacktest/awesome-systematic-trading)\n\n\n# Libraries and packages\n\n*List of **97 libraries and packages** implementing trading bots, backtesters, indicators, pricers, etc. Each library is categorized by its programming language and ordered by descending populatrity (number of stars).*\n\n\n## Backtesting and Live Trading\n\n### General - Event Driven Frameworks\n\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [vnpy](https://github.com/vnpy/vnpy) | Python-based open source quantitative trading system development framework, officially released in January 2015, has grown step by step into a full-featured quantitative trading platform | ![GitHub stars](https://badgen.net/github/stars/vnpy/vnpy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [zipline](https://github.com/quantopian/zipline) | Zipline is a Pythonic algorithmic trading library. It is an event-driven system for backtesting. | ![GitHub stars](https://badgen.net/github/stars/quantopian/zipline) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [backtrader](https://github.com/mementum/backtrader) | Event driven Python Backtesting library for trading strategies | ![GitHub stars](https://badgen.net/github/stars/mementum/backtrader) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [QUANTAXIS](https://github.com/QUANTAXIS/QUANTAXIS) | QUANTAXIS 支持任务调度 分布式部署的 股票/期货/期权/港股/虚拟货币 数据/回测/模拟/交易/可视化/多账户 纯本地量化解决方案 | ![GitHub stars](https://badgen.net/github/stars/QUANTAXIS/QUANTAXIS) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [QuantConnect](https://github.com/QuantConnect/Lean) | Lean Algorithmic Trading Engine by QuantConnect (Python, C#) | ![GitHub stars](https://badgen.net/github/stars/QuantConnect/Lean) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Rqalpha](https://github.com/ricequant/rqalpha) | A extendable, replaceable Python algorithmic backtest && trading framework supporting multiple securities | ![GitHub stars](https://badgen.net/github/stars/ricequant/rqalpha) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [finmarketpy](https://github.com/cuemacro/finmarketpy) | Python library for backtesting trading strategies & analyzing financial markets (formerly pythalesians) | ![GitHub stars](https://badgen.net/github/stars/cuemacro/finmarketpy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [backtesting.py](https://github.com/kernc/backtesting.py) | Backtesting.py is a Python framework for inferring viability of trading strategies on historical (past) data. Improved upon the vision of Backtrader, and by all means surpassingly comparable to other accessible alternatives, Backtesting.py is lightweight, fast, user-friendly, intuitive, interactive, intelligent and, hopefully, future-proof. | ![GitHub stars](https://badgen.net/github/stars/kernc/backtesting.py) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [zvt](https://github.com/zvtvz/zvt) | Modular quant framework | ![GitHub stars](https://badgen.net/github/stars/zvtvz/zvt) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [WonderTrader](https://github.com/wondertrader/wondertrader) | WonderTrader——量化研发交易一站式框架  | ![GitHub stars](https://badgen.net/github/stars/wondertrader/wondertrader) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [nautilus_trader](https://github.com/nautechsystems/nautilus_trader) | A high-performance algorithmic trading platform and event-driven backtester | ![GitHub stars](https://badgen.net/github/stars/nautechsystems/nautilus_trader) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [PandoraTrader](https://github.com/pegasusTrader/PandoraTrader) | High-frequency quantitative trading platform based on c++ development, supporting multiple trading APIs and cross-platform | ![GitHub stars](https://badgen.net/github/stars/pegasusTrader/PandoraTrader) | ![made-with-c++](https://img.shields.io/badge/Made%20with-c++-1f425f.svg) |\n| [HFTBacktest](https://github.com/nkaz001/hftbacktest) | Highly precise backtest on HFT data in Python+Numba | ![GitHub stars](https://badgen.net/github/stars/nkaz001/hftbacktest) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [aat](https://github.com/AsyncAlgoTrading/aat) | An asynchronous, event-driven framework for writing algorithmic trading strategies in python with optional acceleration in C++. It is designed to be modular and extensible, with support for a wide variety of instruments and strategies, live trading across (and between) multiple exchanges. | ![GitHub stars](https://badgen.net/github/stars/AsyncAlgoTrading/aat) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [sdoosa-algo-trade-python](https://github.com/sreenivasdoosa/sdoosa-algo-trade-python) | This project is mainly for newbies into algo trading who are interested in learning to code their own trading algo using python interpreter. | ![GitHub stars](https://badgen.net/github/stars/sreenivasdoosa/sdoosa-algo-trade-python) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [lumibot](https://github.com/Lumiwealth/lumibot) | A very simple yet useful backtesting and sample based live trading framework (a bit slow to run...) | ![GitHub stars](https://badgen.net/github/stars/Lumiwealth/lumibot) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [quanttrader](https://github.com/letianzj/quanttrader) | Backtest and live trading in Python. Event based. Similar to backtesting.py. | ![GitHub stars](https://badgen.net/github/stars/letianzj/quanttrader) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [gobacktest](https://github.com/gobacktest/gobacktest) | A Go implementation of event-driven backtesting framework | ![GitHub stars](https://badgen.net/github/stars/gobacktest/gobacktest) | ![made-with-go](https://img.shields.io/badge/Made%20with-Go-1f425f.svg) |\n| [FlashFunk](https://github.com/HFQR/FlashFunk) | High Performance Runtime in Rust | ![GitHub stars](https://badgen.net/github/stars/HFQR/FlashFunk) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n\n\n### General - Vector Based Frameworks\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [vectorbt](https://github.com/polakowo/vectorbt) | vectorbt takes a novel approach to backtesting: it operates entirely on pandas and NumPy objects, and is accelerated by Numba to analyze any data at speed and scale. This allows for testing of many thousands of strategies in seconds. | ![GitHub stars](https://badgen.net/github/stars/polakowo/vectorbt) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [pysystemtrade](https://github.com/robcarver17/pysystemtrade) | Systematic Trading in python from book Systematic Trading by Rob Carver | ![GitHub stars](https://badgen.net/github/stars/robcarver17/pysystemtrade) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [bt](https://github.com/pmorissette/bt) | Flexible backtesting for Python based on Algo and Strategy Tree | ![GitHub stars](https://badgen.net/github/stars/pmorissette/bt) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n### Cryptocurrencies\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [Freqtrade](https://github.com/freqtrade/freqtrade) | Freqtrade is a free and open source crypto trading bot written in Python. It is designed to support all major exchanges and be controlled via Telegram. It contains backtesting, plotting and money management tools as well as strategy optimization by machine learning. | ![GitHub stars](https://badgen.net/github/stars/freqtrade/freqtrade) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Jesse](https://github.com/jesse-ai/jesse) | Jesse is an advanced crypto trading framework which aims to simplify researching and defining trading strategies. | ![GitHub stars](https://badgen.net/github/stars/jesse-ai/jesse) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [OctoBot](https://github.com/Drakkar-Software/OctoBot) | Cryptocurrency trading bot for TA, arbitrage and social trading with an advanced web interface | ![GitHub stars](https://badgen.net/github/stars/Drakkar-Software/OctoBot) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Kelp](https://github.com/stellar/kelp) | Kelp is a free and open-source trading bot for the Stellar DEX and 100+ centralized exchanges | ![GitHub stars](https://badgen.net/github/stars/stellar/kelp) | ![made-with-go](https://img.shields.io/badge/Made%20with-Go-1f425f.svg) |\n| [openlimits](https://github.com/nash-io/openlimits) | A Rust high performance cryptocurrency trading API with support for multiple exchanges and language wrappers. | ![GitHub stars](https://badgen.net/github/stars/nash-io/openlimits) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n| [bTrader](https://github.com/gabriel-milan/btrader) | Triangle arbitrage trading bot for Binance | ![GitHub stars](https://badgen.net/github/stars/gabriel-milan/btrader) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n| [crypto-crawler-rs](https://github.com/crypto-crawler/crypto-crawler-rs) | Crawl orderbook and trade messages from crypto exchanges | ![GitHub stars](https://badgen.net/github/stars/crypto-crawler/crypto-crawler-rs) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n| [Hummingbot](https://github.com/CoinAlpha/hummingbot) | A client for crypto market making | ![GitHub stars](https://badgen.net/github/stars/CoinAlpha/hummingbot) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [cryptotrader-core](https://github.com/monomadic/cryptotrader-core) | Simple to use Crypto Exchange REST API client in rust. | ![GitHub stars](https://badgen.net/github/stars/monomadic/cryptotrader-core) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n\n## Trading bots\n\n*Trading bots and alpha models. Some of them are old and not maintained.*\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [Blackbird](https://github.com/butor/blackbird) | Blackbird Bitcoin Arbitrage: a long/short market-neutral strategy | ![GitHub stars](https://badgen.net/github/stars/butor/blackbird) | ![made-with-c++](https://img.shields.io/badge/Made%20with-c++-1f425f.svg) |\n| [bitcoin-arbitrage](https://github.com/maxme/bitcoin-arbitrage) | Bitcoin arbitrage - opportunity detector | ![GitHub stars](https://badgen.net/github/stars/maxme/bitcoin-arbitrage) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [ThetaGang](https://github.com/brndnmtthws/thetagang) | ThetaGang is an IBKR bot for collecting money | ![GitHub stars](https://badgen.net/github/stars/brndnmtthws/thetagang) | ![made-with-typescript](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [czsc](https://github.com/waditu/czsc) | 缠中说禅技术分析工具；缠论；股票；期货；Quant；量化交易 | ![GitHub stars](https://badgen.net/github/stars/waditu/czsc) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [R2 Bitcoin Arbitrager](https://github.com/bitrinjani/r2) | R2 Bitcoin Arbitrager is an automatic arbitrage trading system powered by Node.js + TypeScript | ![GitHub stars](https://badgen.net/github/stars/bitrinjani/r2) | ![made-with-typescript](https://img.shields.io/badge/Made%20with-TypeScript-1f425f.svg) |\n| [analyzingalpha](https://github.com/leosmigel/analyzingalpha) | Implementation of simple strategies | ![GitHub stars](https://badgen.net/github/stars/leosmigel/analyzingalpha) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [PyTrendFollow](https://github.com/chrism2671/PyTrendFollow) | PyTrendFollow - systematic futures trading using trend following | ![GitHub stars](https://badgen.net/github/stars/chrism2671/PyTrendFollow) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n## Analytics\n\n### Indicators\n\n*Libraries of indicators to predict future price movements.*\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [ta-lib](https://github.com/mrjbq7/ta-lib) | Perform technical analysis of financial market data | ![GitHub stars](https://badgen.net/github/stars/mrjbq7/ta-lib) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [go-tart](https://github.com/iamjinlei/go-tart) | A Go implementation of the [ta-lib]((https://github.com/mrjbq7/ta-lib) with streaming update support | ![GitHub stars](https://badgen.net/github/stars/iamjinlei/go-tart) | ![made-with-go](https://img.shields.io/badge/Made%20with-go-1f425f.svg) |\n| [pandas-ta](https://github.com/twopirllc/pandas-ta) | Pandas Technical Analysis (Pandas TA) is an easy to use library that leverages the Pandas package with more than 130 Indicators and Utility functions and more than 60 TA Lib Candlestick Patterns | ![GitHub stars](https://badgen.net/github/stars/twopirllc/pandas-ta) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [finta](https://github.com/peerchemist/finta) | Common financial technical indicators implemented in Pandas | ![GitHub stars](https://badgen.net/github/stars/peerchemist/finta) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [ta-rust](https://github.com/greyblake/ta-rs) | Technical analysis library for Rust language | ![GitHub stars](https://badgen.net/github/stars/greyblake/ta-rs) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n\n### Metrics computation\n\n*Librairies of financial metrics.*\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [quantstats](https://github.com/ranaroussi/quantstats) | Portfolio analytics for quants, written in Python | ![GitHub stars](https://badgen.net/github/stars/ranaroussi/quantstats) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [ffn](https://github.com/pmorissette/ffn) | A financial function library for Python | ![GitHub stars](https://badgen.net/github/stars/pmorissette/ffn) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n### Optimization\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [PyPortfolioOpt](https://github.com/robertmartin8/PyPortfolioOpt) | Financial portfolio optimizations in python, including classical efficient frontier, Black-Litterman, Hierarchical Risk Parity | ![GitHub stars](https://badgen.net/github/stars/robertmartin8/PyPortfolioOpt) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Riskfolio-Lib](https://github.com/dcajasn/Riskfolio-Lib) | Portfolio Optimization and Quantitative Strategic Asset Allocation in Python | ![GitHub stars](https://badgen.net/github/stars/dcajasn/Riskfolio-Lib) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [empyrial](https://github.com/ssantoshp/Empyrial) | Empyrial is a Python-based open-source quantitative investment library dedicated to financial institutions and retail investors, officially released in March 2021 | ![GitHub stars](https://badgen.net/github/stars/ssantoshp/Empyrial) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Deepdow](https://github.com/jankrepl/deepdow) | Python package connecting portfolio optimization and deep learning. Its goal is to facilitate research of networks that perform weight allocation in one forward pass. | ![GitHub stars](https://badgen.net/github/stars/jankrepl/deepdow) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [spectre](https://github.com/Heerozh/spectre) | Portfolio Optimization and Quantitative Strategic Asset Allocation in Python | ![GitHub stars](https://badgen.net/github/stars/Heerozh/spectre) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n### Pricing\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [tf-quant-finance](https://github.com/google/tf-quant-finance) | High-performance TensorFlow library for quantitative finance from Google | ![GitHub stars](https://badgen.net/github/stars/google/tf-quant-finance) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [FinancePy](https://github.com/domokane/FinancePy) | A Python Finance Library that focuses on the pricing and risk-management of Financial Derivatives, including fixed-income, equity, FX and credit derivatives | ![GitHub stars](https://badgen.net/github/stars/domokane/FinancePy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [PyQL](https://github.com/enthought/pyql) | Python wrapper of the famous pricing library QuantLib | ![GitHub stars](https://badgen.net/github/stars/enthought/pyql) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n### Risk\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [pyfolio](https://github.com/quantopian/pyfolio) | Portfolio and risk analytics in Python | ![GitHub stars](https://badgen.net/github/stars/quantopian/pyfolio) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n\n## Broker APIs\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [ccxt](https://github.com/ccxt/ccxt) | A JavaScript / Python / PHP cryptocurrency trading API with support for more than 100 bitcoin/altcoin exchanges | ![GitHub stars](https://badgen.net/github/stars/ccxt/ccxt) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Ib_insync](https://github.com/erdewit/ib_insync) | Python sync/async framework for Interactive Brokers. | ![GitHub stars](https://badgen.net/github/stars/erdewit/ib_insync) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Coinnect](https://github.com/hugues31/coinnect) | Coinnect is a Rust library aiming to provide a complete access to main crypto currencies exchanges via REST API. | ![GitHub stars](https://badgen.net/github/stars/hugues31/coinnect) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n| [PENDAX](https://github.com/CompendiumFi/PENDAX-SDK) | Javascript SDK for Trading, Data, and Websockets for FTX, FTXUS, OKX, Bybit, & More. | ![GitHub stars](https://badgen.net/github/stars/CompendiumFi/PENDAX-SDK) | ![made-with-javascript](https://img.shields.io/badge/Made%20with-Javascript-1f425f.svg) |\n\n\n## Data Sources\n\n### General\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [OpenBB Terminal](https://github.com/OpenBB-finance/OpenBBTerminal) | Investment Research for Everyone, Anywhere. | ![GitHub stars](https://badgen.net/github/stars/OpenBB-finance/OpenBBTerminal) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [TuShare](https://github.com/waditu/tushare) | TuShare is a utility for crawling historical data of China stocks | ![GitHub stars](https://badgen.net/github/stars/waditu/tushare) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [yfinance](https://github.com/ranaroussi/yfinance) | yfinance offers a threaded and Pythonic way to download market data from Yahoo!Ⓡ finance. | ![GitHub stars](https://badgen.net/github/stars/ranaroussi/yfinance) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [AkShare](https://github.com/akfamily/akshare) | AKShare is an elegant and simple financial data interface library for Python, built for human beings! | ![GitHub stars](https://badgen.net/github/stars/akfamily/akshare) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [pandas-datareader](https://github.com/pydata/pandas-datareader) | Up to date remote data access for pandas, works for multiple versions of pandas. | ![GitHub stars](https://badgen.net/github/stars/pydata/pandas-datareader) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Quandl](https://github.com/quandl/quandl-python) | Get millions of financial and economic dataset from hundreds of publishers via a single free API. | ![GitHub stars](https://badgen.net/github/stars/quandl/quandl-python) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [findatapy](https://github.com/cuemacro/findatapy) | findatapy creates an easy to use Python API to download market data from many sources including Quandl, Bloomberg, Yahoo, Google etc. using a unified high level interface. | ![GitHub stars](https://badgen.net/github/stars/cuemacro/findatapy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Investpy](https://github.com/alvarobartt/investpy) | Financial Data Extraction from Investing.com with Python | ![GitHub stars](https://badgen.net/github/stars/alvarobartt/investpy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Fundamental Analysis Data](https://github.com/JerBouma/FundamentalAnalysis) | Fully-fledged Fundamental Analysis package capable of collecting 20 years of Company Profiles, Financial Statements, Ratios and Stock Data of 20.000+ companies. | ![GitHub stars](https://badgen.net/github/stars/JerBouma/FundamentalAnalysis) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Wallstreet](https://github.com/mcdallas/wallstreet) | Wallstreet: Real time Stock and Option tools | ![GitHub stars](https://badgen.net/github/stars/mcdallas/wallstreet) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n### Cryptocurrencies\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [Cryptofeed](https://github.com/bmoscon/cryptofeed) | Cryptocurrency Exchange Websocket Data Feed Handler with Asyncio | ![GitHub stars](https://badgen.net/github/stars/bmoscon/cryptofeed) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Gekko-Datasets](https://github.com/xFFFFF/Gekko-Datasets) | Gekko trading bot dataset dumps. Download and use history files in SQLite format. | ![GitHub stars](https://badgen.net/github/stars/xFFFFF/Gekko-Datasets) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [CryptoInscriber](https://github.com/Optixal/CryptoInscriber) | A live crypto currency historical trade data blotter. Download live historical trade data from any crypto exchange. | ![GitHub stars](https://badgen.net/github/stars/Optixal/CryptoInscriber) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Crypto Lake](https://github.com/crypto-lake/lake-api) | High frequency order book & trade data for crypto | ![GitHub stars](https://badgen.net/github/stars/crypto-lake/lake-api) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n## Data Science\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [TensorFlow](https://github.com/tensorflow/tensorflow) | Fundamental algorithms for scientific computing in Python | ![GitHub stars](https://badgen.net/github/stars/tensorflow/tensorflow) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Pytorch](https://github.com/pytorch/pytorch) | Tensors and Dynamic neural networks in Python with strong GPU acceleration | ![GitHub stars](https://badgen.net/github/stars/pytorch/pytorch) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Keras](https://github.com/keras-team/keras) | The most user friendly Deep Learning for humans in Python | ![GitHub stars](https://badgen.net/github/stars/keras-team/keras) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Scikit-learn](https://github.com/scikit-learn/scikit-learn) | Machine learning in Python | ![GitHub stars](https://badgen.net/github/stars/scikit-learn/scikit-learn) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Pandas](https://github.com/pandas-dev/pandas) | Flexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more | ![GitHub stars](https://badgen.net/github/stars/pandas-dev/pandas) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Numpy](https://github.com/numpy/numpy) | The fundamental package for scientific computing with Python | ![GitHub stars](https://badgen.net/github/stars/numpy/numpy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Scipy](https://github.com/scipy/scipy) | Fundamental algorithms for scientific computing in Python | ![GitHub stars](https://badgen.net/github/stars/scipy/scipy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [PyMC](https://github.com/pymc-devs/pymc) | Probabilistic Programming in Python: Bayesian Modeling and Probabilistic Machine Learning with Aesara | ![GitHub stars](https://badgen.net/github/stars/pymc-devs/pymc) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Cvxpy](https://github.com/cvxpy/cvxpy) | A Python-embedded modeling language for convex optimization problems. | ![GitHub stars](https://badgen.net/github/stars/cvxpy/cvxpy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n## Databases\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [Marketstore](https://github.com/alpacahq/marketstore) | DataFrame Server for Financial Timeseries Data | ![GitHub stars](https://badgen.net/github/stars/alpacahq/marketstore) | ![made-with-go](https://img.shields.io/badge/Made%20with-Go-1f425f.svg) |\n| [Tectonicdb](https://github.com/0b01/tectonicdb) | Tectonicdb is a fast, highly compressed standalone database and streaming protocol for order book ticks. | ![GitHub stars](https://badgen.net/github/stars/0b01/tectonicdb) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n| [ArcticDB (Man Group)](https://github.com/man-group/arcticdb) | High performance datastore for time series and tick data | ![GitHub stars](https://badgen.net/github/stars/man-group/ArcticDB) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n## Graph Computation\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [Ray](https://github.com/ray-project/ray) | An open source framework that provides a simple, universal API for building distributed applications. | ![GitHub stars](https://badgen.net/github/stars/ray-project/ray) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Dask](https://github.com/dask/dask) | Parallel computing with task scheduling in Python with a Pandas like API | ![GitHub stars](https://badgen.net/github/stars/dask/dask) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Incremental (JaneStreet)](https://github.com/janestreet/incremental) | Incremental is a library that gives you a way of building complex computations that can update efficiently in response to their inputs changing, inspired by the work of Umut Acar et. al. on self-adjusting computations. Incremental can be useful in a number of applications | ![GitHub stars](https://badgen.net/github/stars/janestreet/incremental) | ![made-with-ocaml](https://img.shields.io/badge/Made%20with-Ocaml-1f425f.svg) |\n| [Man MDF](https://github.com/man-group/mdf) | Data-flow programming toolkit for Python | ![GitHub stars](https://badgen.net/github/stars/man-group/mdf) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [GraphKit](https://github.com/yahoo/graphkit) | A lightweight Python module for creating and running ordered graphs of computations. | ![GitHub stars](https://badgen.net/github/stars/yahoo/graphkit) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Tributary](https://github.com/timkpaine/tributary) | Streaming reactive and dataflow graphs in Python | ![GitHub stars](https://badgen.net/github/stars/timkpaine/tributary) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n## Machine Learning\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [QLib (Microsoft)](https://github.com/microsoft/qlib) | Qlib is an AI-oriented quantitative investment platform, which aims to realize the potential, empower the research, and create the value of AI technologies in quantitative investment. With Qlib, you can easily try your ideas to create better Quant investment strategies. An increasing number of SOTA Quant research works/papers are released in Qlib. | ![GitHub stars](https://badgen.net/github/stars/microsoft/qlib) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [FinRL](https://github.com/AI4Finance-Foundation/FinRL) | FinRL is the first open-source framework to demonstrate the great potential of applying deep reinforcement learning in quantitative finance. | ![GitHub stars](https://badgen.net/github/stars/AI4Finance-Foundation/FinRL) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [MlFinLab (Hudson & Thames)](https://github.com/hudson-and-thames/mlfinlab) | MlFinLab helps portfolio managers and traders who want to leverage the power of machine learning by providing reproducible, interpretable, and easy to use tools. | ![GitHub stars](https://badgen.net/github/stars/hudson-and-thames/mlfinlab) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [TradingGym](https://github.com/Yvictor/TradingGym) | Trading and Backtesting environment for training reinforcement learning agent or simple rule base algo. | ![GitHub stars](https://badgen.net/github/stars/Yvictor/TradingGym) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Stock Trading Bot using Deep Q-Learning](https://github.com/pskrunner14/trading-bot) | Stock Trading Bot using Deep Q-Learning | ![GitHub stars](https://badgen.net/github/stars/pskrunner14/trading-bot) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n## TimeSeries Analysis\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [Facebook Prophet](https://github.com/facebook/prophet) | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. | ![GitHub stars](https://badgen.net/github/stars/facebook/prophet) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [statsmodels](https://github.com/statsmodels/statsmodels) | Python module that allows users to explore data, estimate statistical models, and perform statistical tests. | ![GitHub stars](https://badgen.net/github/stars/statsmodels/statsmodels) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [tsfresh](https://github.com/blue-yonder/tsfresh) | Automatic extraction of relevant features from time series. | ![GitHub stars](https://badgen.net/github/stars/blue-yonder/tsfresh) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [pmdarima](https://github.com/alkaline-ml/pmdarima) | A statistical library designed to fill the void in Python's time series analysis capabilities, including the equivalent of R's auto.arima function. | ![GitHub stars](https://badgen.net/github/stars/alkaline-ml/pmdarima) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n## Visualization\n\n| Repository | Description | Stars | Made with |\n|------------|-------------|-------|-----------|\n| [D-Tale (Man Group)](https://github.com/man-group/dtale) | D-Tale is the combination of a Flask back-end and a React front-end to bring you an easy way to view & analyze Pandas data structures. | ![GitHub stars](https://badgen.net/github/stars/man-group/dtale) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [mplfinance](https://github.com/matplotlib/mplfinance) | Financial Markets Data Visualization using Matplotlib | ![GitHub stars](https://badgen.net/github/stars/matplotlib/mplfinance) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [btplotting](https://github.com/happydasch/btplotting) | btplotting provides plotting for backtests, optimization results and live data from backtrader. | ![GitHub stars](https://badgen.net/github/stars/happydasch/btplotting) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n# Strategies\n\n*List of **40+ academic papers** describing original systematic trading strategies. Each strategy is categorized by its asset class and ordered by descending Sharpe ratio.*\n\n👉 Strategies are now hosted [here](https://paperswithbacktest.com).\n\n\nPrevious list of strategies:\n\n## Bonds, commodities, currencies, equities\n\n| Title       | Sharpe Ratio | Volatility | Rebalancing | Implementation | Source |\n|-------------|--------------|------------|-------------|----------------|--------|\n| Time Series Momentum Effect | `0.576` | `20.5%` | `Monthly` | [QuantConnect](./static/strategies/time-series-momentum-effect.py) | [Paper](https://pages.stern.nyu.edu/~lpederse/papers/TimeSeriesMomentum.pdf) |\n| Short Term Reversal with Futures | `-0.05` | `12.3%` | `Weekly` | [QuantConnect](./static/strategies/asset-class-momentum-rotational-system.py) | [Paper](https://ideas.repec.org/a/eee/jbfina/v28y2004i6p1337-1361.html) |\n\n## Bonds, commodities, equities, REITs\n\n|  Title       | Sharpe Ratio | Volatility | Rebalancing | Implementation | Source |\n|--------------|--------------|------------|-------------|----------------|--------|\n| Asset Class Trend-Following | `0.502` | `10.4%` | `Monthly` | [QuantConnect](./static/strategies/asset-class-trend-following.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=962461) |\n| Momentum Asset Allocation Strategy | `0.321` | `11%` | `Monthly` | [QuantConnect](./static/strategies/asset-class-trend-following.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1585517) |\n\n## Bonds, equities\n\n|  Title       | Sharpe Ratio | Volatility | Rebalancing | Implementation | Source |\n|--------------|--------------|------------|-------------|----------------|--------|\n| Paired Switching | `0.691` | `9.5%` | `Quarterly` | [QuantConnect](./static/strategies/paired-switching.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1917044) |\n| FED Model | `0.369` | `14.3%` | `Monthly` | [QuantConnect](./static/strategies/fed-model.py) | [Paper](https://www.researchgate.net/publication/228267011_The_FED_Model_and_Expected_Asset_Returns) |\n\n## Bonds, equities, REITs\n\n|  Title       | Sharpe Ratio | Volatility | Rebalancing | Implementation | Source |\n|--------------|--------------|------------|-------------|----------------|--------|\n| Value and Momentum Factors across Asset Classes | `0.155` | `9.8%` | `Monthly` | [QuantConnect](./static/strategies/value-and-momentum-factors-across-asset-classes.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1079975) |\n\n## Commodities\n\n|  Title       | Sharpe Ratio | Volatility | Rebalancing | Implementation | Source |\n|--------------|--------------|------------|-------------|----------------|--------|\n| Skewness Effect in Commodities | `0.482` | `17.7%` | `Monthly` | [QuantConnect](./static/strategies/skewness-effect-in-commodities.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2671165) |\n| Return Asymmetry Effect in Commodity Futures | `0.239` | `13.4%` | `Monthly` | [QuantConnect](./static/strategies/return-asymmetry-effect-in-commodity-futures.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3918896) |\n| Momentum Effect in Commodities | `0.14` | `20.3%` | `Monthly` | [QuantConnect](./static/strategies/momentum-effect-in-commodities.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=702281) |\n| Term Structure Effect in Commodities | `0.128` | `23.1%` | `Monthly` | [QuantConnect](./static/strategies/term-structure-effect-in-commodities.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1127213) |\n| Trading WTI/BRENT Spread | `-0.199` | `11.6%` | `Daily` | [QuantConnect](./static/strategies/trading-wti-brent-spread.py) | [Paper](https://link.springer.com/article/10.1057/jdhf.2009.24) |\n\n## Cryptos\n\n|  Title       | Sharpe Ratio | Volatility | Rebalancing | Implementation | Source |\n|--------------|--------------|------------|-------------|----------------|--------|\n| Overnight Seasonality in Bitcoin | `0.892` | `20.8%` | `Intraday` | [QuantConnect](./static/strategies/intraday-seasonality-in-bitcoin.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4081000) |\n| Rebalancing Premium in Cryptocurrencies | `0.698` | `27.5%` | `Daily` | [QuantConnect](./static/strategies/rebalancing-premium-in-cryptocurrencies.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3982120) |\n\n## Currencies\n\n|  Title       | Sharpe Ratio | Volatility | Rebalancing | Implementation | Source |\n|--------------|--------------|------------|-------------|----------------|--------|\n| FX Carry Trade | `0.254` | `7.8%` | `Monthly` | [QuantConnect](./static/strategies/fx-carry-trade.py) | [Paper](http://globalmarkets.db.com/new/docs/dbCurrencyReturns_March2009.pdf) |\n| Dollar Carry Trade | `0.113` | `5.8%` | `Monthly` | [QuantConnect](./static/strategies/dollar-carry-trade.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1541230) |\n| Currency Momentum Factor | `-0.01` | `6.7%` | `Monthly` | [QuantConnect](./static/strategies/currency-momentum-factor.py) | [Paper](http://globalmarkets.db.com/new/docs/dbCurrencyReturns_March2009.pdf) |\n| Currency Value Factor – PPP Strategy | `-0.103` | `5%` | `Quarterly` | [QuantConnect](./static/strategies/currency-value-factor-ppp-strategy.py) | [Paper](http://globalmarkets.db.com/new/docs/dbCurrencyReturns_March2009.pdf) |\n\n## Equities\n\n|  Title       | Sharpe Ratio | Volatility | Rebalancing | Implementation | Source |\n|--------------|--------------|------------|-------------|----------------|--------|\n| Asset Growth Effect | `0.835` | `10.2%` | `Yearly` | [QuantConnect](./static/strategies/asset-growth-effect.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1335524) |\n| Short Term Reversal Effect in Stocks | `0.816` | `21.4%` | `Weekly` | [QuantConnect](./static/strategies/short-term-reversal-in-stocks.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1605049) |\n| Reversal During Earnings-Announcements | `0.785` | `25.7%` | `Daily` | [QuantConnect](./static/strategies/reversal-during-earnings-announcements.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2275982) |\n| Size Factor – Small Capitalization Stocks Premium | `0.747` | `11.1%` | `Yearly` | [QuantConnect](./static/strategies/small-capitalization-stocks-premium-anomaly.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3177539) |\n| Low Volatility Factor Effect in Stocks | `0.717` | `11.5%` | `Monthly` | [QuantConnect](./static/strategies/low-volatility-factor-effect-in-stocks.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=980865) |\n| How to Use Lexical Density of Company Filings | `0.688` | `10.4%` | `Monthly` | [QuantConnect](./static/strategies/how-to-use-lexical-density-of-company-filings.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3921091) |\n| Volatility Risk Premium Effect | `0.637` | `13.2%` | `Monthly` | [QuantConnect](./static/strategies/volatility-risk-premium-effect.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=189840) |\n| Pairs Trading with Stocks | `0.634` | `8.5%` | `Daily` | [QuantConnect](./static/strategies/pairs-trading-with-stocks.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=141615) |\n| Crude Oil Predicts Equity Returns | `0.599` | `11.5%` | `Monthly` | [QuantConnect](./static/strategies/crude-oil-predicts-equity-returns.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=460500) |\n| Betting Against Beta Factor in Stocks | `0.594` | `18.9%` | `Monthly` | [QuantConnect](./static/strategies/betting-against-beta-factor-in-stocks.py) | [Paper](https://pages.stern.nyu.edu/~lpederse/papers/BettingAgainstBeta.pdf) |\n| Trend-following Effect in Stocks | `0.569` | `15.2%` | `Daily` | [QuantConnect](./static/strategies/trend-following-effect-in-stocks.py) | [Paper](https://www.cis.upenn.edu/~mkearns/finread/trend.pdf) |\n| ESG Factor Momentum Strategy | `0.559` | `21.8%` | `Monthly` | [QuantConnect](./static/strategies/esg-factor-momentum-strategy.py) | [Paper](https://www.semanticscholar.org/paper/Can-ESG-Add-Alpha-An-Analysis-of-ESG-Tilt-and-Nagy-Kassam/64f77da4f8ce5906a73ffe4e9eec7c49c0960acc) |\n| Value (Book-to-Market) Factor | `0.526` | `11.9%` | `Monthly` | [QuantConnect](./static/strategies/value-book-to-market-factor.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2595747) |\n| Soccer Clubs’ Stocks Arbitrage | `0.515` | `14.2%` | `Daily` | [QuantConnect](./static/strategies/soccer-clubs-stocks-arbitrage.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1343685) |\n| Synthetic Lending Rates Predict Subsequent Market Return | `0.494` | `13.7%` | `Daily` | [QuantConnect](./static/strategies/synthetic-lending-rates-predict-subsequent-market-return.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3976307) |\n| Option-Expiration Week Effect | `0.452` | `5%` | `Weekly` | [QuantConnect](./static/strategies/option-expiration-week-effect.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1571786) |\n| Dispersion Trading | `0.432` | `8.1%` | `Monthly` | [QuantConnect](./static/strategies/dispersion-trading.py) | [Paper](https://www.academia.edu/16327015/EQUILIBRIUM_INDEX_AND_SINGLE_STOCK_VOLATILITY_RISK_PREMIA) |\n| Momentum in Mutual Fund Returns | `0.414` | `13.6%` | `Quarterly` | [QuantConnect](./static/strategies/momentum-in-mutual-fund-returns.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1462408) |\n| Sector Momentum – Rotational System | `0.401` | `14.1%` | `Monthly` | [QuantConnect](./static/strategies/sector-momentum-rotational-system.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1585517) |\n| Combining Smart Factors Momentum and Market Portfolio | `0.388` | `8.2%` | `Monthly` | [QuantConnect](./static/strategies/combining-smart-factors-momentum-and-market-portfolio.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3745517) |\n| Momentum and Reversal Combined with Volatility Effect in Stocks | `0.375` | `17%` | `Monthly` | [QuantConnect](./static/strategies/momentum-and-reversal-combined-with-volatility-effect-in-stocks.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1679464) |\n| Market Sentiment and an Overnight Anomaly | `0.369` | `3.6%` | `Daily` | [QuantConnect](./static/strategies/market-sentiment-and-an-overnight-anomaly.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3829582) |\n| January Barometer | `0.365` | `7.4%` | `Monthly` | [QuantConnect](./static/strategies/january-barometer.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1436516) |\n| R&D Expenditures and Stock Returns | `0.354` | `8.1%` | `Yearly` | [QuantConnect](./static/strategies/rd-expenditures-and-stock-returns.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=227564) |\n| Value Factor – CAPE Effect within Countries | `0.351` | `20.2%` | `Yearly` | [QuantConnect](./static/strategies/value-factor-effect-within-countries.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2129474) |\n| 12 Month Cycle in Cross-Section of Stocks Returns | `0.34` | `43.7%` | `Monthly` | [QuantConnect](./static/strategies/12-month-cycle-in-cross-section-of-stocks-returns.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=687022) |\n| Turn of the Month in Equity Indexes | `0.305` | `7.2%` | `Daily` | [QuantConnect](./static/strategies/turn-of-the-month-in-equity-indexes.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=917884) |\n| Payday Anomaly | `0.269` | `3.8%` | `Daily` | [QuantConnect](./static/strategies/payday-anomaly.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3257064) |\n| Pairs Trading with Country ETFs | `0.257` | `5.7%` | `Daily` | [QuantConnect](./static/strategies/pairs-trading-with-country-etfs.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1958546) |\n| Residual Momentum Factor | `0.24` | `9.7%` | `Monthly` | [QuantConnect](./static/strategies/residual-momentum-factor.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2319861) |\n| Earnings Announcement Premium | `0.192` | `3.7%` | `Monthly` | [QuantConnect](./static/strategies/earnings-announcement-premium.py) | [Paper](https://www.nber.org/system/files/working_papers/w13090/w13090.pdf) |\n| ROA Effect within Stocks | `0.155` | `8.7%` | `Monthly` | [QuantConnect](./static/strategies/roa-effect-within-stocks.py) | [Paper](https://static1.squarespace.com/static/5e6033a4ea02d801f37e15bb/t/5f61583e88f43b7d5b7196b5/1600215105801/Chen_Zhang_JF.pdf) |\n| 52-Weeks High Effect in Stocks | `0.153` | `19%` | `Monthly` | [QuantConnect](./static/strategies/52-weeks-high-effect-in-stocks.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1787378) |\n| Combining Fundamental FSCORE and Equity Short-Term Reversals | `0.153` | `17.6%` | `Monthly` | [QuantConnect](./static/strategies/combining-fundamental-fscore-and-equity-short-term-reversals.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3097420) |\n| Betting Against Beta Factor in International Equities | `0.142` | `9.1%` | `Monthly` | [QuantConnect](./static/strategies/betting-against-beta-factor-in-country-equity-indexes.py) | [Paper](https://pages.stern.nyu.edu/~lpederse/papers/BettingAgainstBeta.pdf) |\n| Consistent Momentum Strategy | `0.128` | `28.8%` | `6 Months` | [QuantConnect](./static/strategies/consistent-momentum-strategy.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2652592) |\n| Short Interest Effect – Long-Short Version | `0.079` | `6.6%` | `Monthly` | [QuantConnect](./static/strategies/short-interest-effect-long-short-version.py) | [Paper](https://www.semanticscholar.org/paper/Why-Do-Short-Interest-Levels-Predict-Stock-Returns-Boehmer-Erturk/06418ef437dc7156229532a97d0f8392373eb297?p2df) |\n| Momentum Factor Combined with Asset Growth Effect | `0.058` | `25.1%` | `Monthly` | [QuantConnect](./static/strategies/momentum-factor-combined-with-asset-growth-effect.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1684767) |\n| Momentum Factor Effect in Stocks | `-0.008` | `21.8%` | `Monthly` | [QuantConnect](./static/strategies/momentum-factor-effect-in-stocks.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2435323) |\n| Momentum Factor and Style Rotation Effect | `-0.056` | `10%` | `Monthly` | [QuantConnect](./static/strategies/momentum-factor-and-style-rotation-effect.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1276815) |\n| Earnings Announcements Combined with Stock Repurchases | `-0.16` | `0.1%` | `Daily` | [QuantConnect](./static/strategies/earnings-announcements-combined-with-stock-repurchases.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2589966) |\n| Earnings Quality Factor | `-0.18` | `28.7%` | `Yearly` | [QuantConnect](./static/strategies/earnings-quality-factor.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2179247) |\n| Accrual Anomaly | `-0.272` | `13.7%` | `Yearly` | [QuantConnect](./static/strategies/accrual-anomaly.py) | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=546108) |\n| ESG, Price Momentum and Stochastic Optimization | `N/A` | `N/A` | `Monthly` |  | [Paper](https://quantpedia.com/strategies/esg-price-momentum-and-stochastic-optimization/) |\n| The Positive Similarity of Company Filings and Stock Returns | `N/A` | `N/A` | `Monthly` |  | [Paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3690461) |\n\n# Books\n\nA comprehensive list of **55 books** for quantitative traders.\n\n\n## Beginner\n\n|  Title   | Reviews | Rating |\n|----------|---------|--------|\n| [A Beginner’s Guide to the Stock Market: Everything You Need to Start Making Money Today - Matthew R. Kratter](https://amzn.to/3QN2VdU) | ![](https://badgen.net/badge/reviews/14%20161/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n| [How to Day Trade for a Living: A Beginner’s Guide to Trading Tools and Tactics, Money Management, Discipline and Trading Psychology - Andrew Aziz](https://amzn.to/3bmehFv) | ![](https://badgen.net/badge/reviews/12%20278/blue) | ![](https://badgen.net/badge/rating/4.5/blue) |\n| [The Little Book of Common Sense Investing: The Only Way to Guarantee Your Fair Share of Stock Market Returns - John C. Bogle](https://amzn.to/3A4mgkR) | ![](https://badgen.net/badge/reviews/6%20969/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [Investing QuickStart Guide: The Simplified Beginner’s Guide to Successfully Navigating the Stock Market, Growing Your Wealth & Creating a Secure Financial Future - Ted D. Snow](https://amzn.to/3A5aRkX) | ![](https://badgen.net/badge/reviews/2%20537/blue) | ![](https://badgen.net/badge/rating/4.5/blue) |\n| [Day Trading QuickStart Guide: The Simplified Beginner’s Guide to Winning Trade Plans, Conquering the Markets, and Becoming a Successful Day Trader - Troy Noonan](https://amzn.to/3HPZijw) | ![](https://badgen.net/badge/reviews/1%20229/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n| [Introduction To Algo Trading: How Retail Traders Can Successfully Compete With Professional Traders - Kevin J Davey](https://amzn.to/39Tf7JC) | ![](https://badgen.net/badge/reviews/131/blue) | ![](https://badgen.net/badge/rating/4/blue) |\n| [Algorithmic Trading and DMA: An introduction to direct access trading strategies - Barry Johnson](https://amzn.to/3xYb0UN) | ![](https://badgen.net/badge/reviews/69/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n\n\n## Biography\n\n|  Title   | Reviews | Rating |\n|----------|---------|--------|\n| [My Life as a Quant: Reflections on Physics and Finance - Emanuel Derman](https://amzn.to/3A8KudR) | ![](https://badgen.net/badge/reviews/192/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [How I Became a Quant: Insights from 25 of Wall Street’s Elite: - Barry Schachter](https://amzn.to/3Alf8kz) | ![](https://badgen.net/badge/reviews/27/blue) | ![](https://badgen.net/badge/rating/3.7/blue) |\n\n\n\n## Coding\n\n|  Title   | Reviews | Rating |\n|----------|---------|--------|\n| [Python for Finance: Mastering Data-Driven Finance - Yves Hilpisch](https://amzn.to/3NhkTlP) | ![](https://badgen.net/badge/reviews/249/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [Trading Evolved: Anyone can Build Killer Trading Strategies in Python - Andreas F. Clenow](https://amzn.to/3A0jcGB) | ![](https://badgen.net/badge/reviews/173/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Python for Algorithmic Trading: From Idea to Cloud Deployment - Yves Hilpisch](https://amzn.to/3bpkd0C) | ![](https://badgen.net/badge/reviews/90/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n| [Algorithmic Trading with Python: Quantitative Methods and Strategy Development - Chris Conlan](https://amzn.to/3u3cxYo) | ![](https://badgen.net/badge/reviews/48/blue) | ![](https://badgen.net/badge/rating/4.2/blue) |\n| [Learn Algorithmic Trading: Build and deploy algorithmic trading systems and strategies using Python and advanced data analysis - Sebastien Donadio](https://amzn.to/3NqNghA) | ![](https://badgen.net/badge/reviews/46/blue) | ![](https://badgen.net/badge/rating/4.1/blue) |\n\n\n## Crypto\n\n|  Title   | Reviews | Rating |\n|----------|---------|--------|\n| [The Bitcoin Standard: The Decentralized Alternative to Central Banking - Saifedean Ammous](https://amzn.to/3QMJgec) | ![](https://badgen.net/badge/reviews/5%20136/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [Bitcoin Billionaires: A True Story of Genius, Betrayal, and Redemption - Ben Mezrich](https://amzn.to/39SkdWt) | ![](https://badgen.net/badge/reviews/1%20787/blue) | ![](https://badgen.net/badge/rating/4.5/blue) |\n| [Mastering Bitcoin: Programming the Open Blockchain - Andreas M. Antonopoulos](https://amzn.to/3NniZ3p) | ![](https://badgen.net/badge/reviews/955/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [Why Buy Bitcoin: Investing Today in the Money of Tomorrow - Andy Edstrom](https://amzn.to/3OMcKqZ) | ![](https://badgen.net/badge/reviews/192/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n\n\n## General\n\n|  Title   | Reviews | Rating |\n|----------|---------|--------|\n| [The Intelligent Investor: The Definitive Book on Value Investing - Benjamin Graham, Jason Zweig](https://www.amazon.fr/gp/product/0060555661/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0060555661&linkId=aba73910e4e3873b6cc8364487662bd6) | ![](https://badgen.net/badge/reviews/38%20087/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [How I Invest My Money: Finance experts reveal how they save, spend, and invest - Joshua Brown, Brian Portnoy](https://amzn.to/3A4rsoU) | ![](https://badgen.net/badge/reviews/892/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Naked Forex: High-Probability Techniques for Trading Without Indicators - Alex Nekritin](https://amzn.to/3NkrAUj) | ![](https://badgen.net/badge/reviews/720/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [The Four Pillars of Investing: Lessons for Building a Winning Portfolio - William J. Bernstein](https://www.amazon.fr/gp/product/B0041842TW/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=B0041842TW&linkId=d9bc2fec4f3faa41ca4f24aed3c72122) | ![](https://badgen.net/badge/reviews/441/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [Option Volatility and Pricing: Advanced Trading Strategies and Techniques, 2nd Edition - Sheldon Natenberg](https://amzn.to/3btOxXL) | ![](https://badgen.net/badge/reviews/388/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [The Art and Science of Technical Analysis: Market Structure, Price Action, and Trading Strategies - Adam Grimes](https://www.amazon.fr/gp/product/1118115120/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1118115120&linkId=d5dc1f0e6727b2663d2186a110a31ad0) | ![](https://badgen.net/badge/reviews/305/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [The New Trading for a Living: Psychology, Discipline, Trading Tools and Systems, Risk Control, Trade Management (Wiley Trading) - Alexander Elder](https://www.amazon.fr/gp/product/1118467450/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1118467450&linkId=67ee502653bc52a5240ced9fc88eb76d) | ![](https://badgen.net/badge/reviews/242/blue) | ![](https://badgen.net/badge/rating/4.5/blue) |\n| [Building Winning Algorithmic Trading Systems: A Trader’s Journey From Data Mining to Monte Carlo Simulation to Live Trading (Wiley Trading) - Kevin J Davey](https://amzn.to/39QnsxA) | ![](https://badgen.net/badge/reviews/163/blue) | ![](https://badgen.net/badge/rating/4.2/blue) |\n| [Systematic Trading: A unique new method for designing trading and investing systems - Robert Carver](https://www.amazon.fr/gp/product/0857194453/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0857194453&linkId=32d8bffc32c01041cde066bacab76c04) | ![](https://badgen.net/badge/reviews/123/blue) | ![](https://badgen.net/badge/rating/4.2/blue) |\n| [Quantitative Momentum: A Practitioner’s Guide to Building a Momentum-Based Stock Selection System (Wiley Finance) - Wesley R. Gray, Jack R. Vogel](https://www.amazon.fr/gp/product/111923719X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=111923719X&linkId=b825cb65462a4a9254af3b7dc5328131) | ![](https://badgen.net/badge/reviews/105/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Algorithmic Trading: Winning Strategies and Their Rationale - Ernest P. Chan](https://amzn.to/3xWi8kd) | ![](https://badgen.net/badge/reviews/100/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Leveraged Trading: A professional approach to trading FX, stocks on margin, CFDs, spread bets and futures for all traders - Robert Carver](https://amzn.to/3Nhl6p7) | ![](https://badgen.net/badge/reviews/98/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n| [Trading Systems: A New Approach to System Development and Portfolio Optimisation - Emilio Tomasini, Urban Jaekle](https://www.amazon.fr/gp/product/1905641796/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1905641796&linkId=61e6634242c497498338f73641ce0a80) | ![](https://badgen.net/badge/reviews/67/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Trading and Exchanges: Market Microstructure for Practitioners - Larry Harris](https://www.amazon.fr/gp/product/0195144708/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0195144708&linkId=e47e596fc0696cbd624726cce05b4500) | ![](https://badgen.net/badge/reviews/61/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Trading Systems 2nd edition: A new approach to system development and portfolio optimisation - Emilio Tomasini, Urban Jaekle](https://www.amazon.fr/gp/product/085719755X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=085719755X&linkId=97aa558484a8dc2bf57a5296e7f38cad) | ![](https://badgen.net/badge/reviews/42/blue) | ![](https://badgen.net/badge/rating/4/blue) |\n| [Machine Trading: Deploying Computer Algorithms to Conquer the Markets - Ernest P. Chan](https://amzn.to/3OIBe4o) | ![](https://badgen.net/badge/reviews/53/blue) | ![](https://badgen.net/badge/rating/4/blue) |\n| [Quantitative Equity Portfolio Management: An Active Approach to Portfolio Construction and Management (McGraw-Hill Library of Investment and Finance) - Ludwig B Chincarini, Daehwan Kim](https://amzn.to/3yl9u0c) | ![](https://badgen.net/badge/reviews/51/blue) | ![](https://badgen.net/badge/rating/4.5/blue) |\n| [Active Portfolio Management: A Quantitative Approach for Producing Superior Returns and Controlling Risk - Richard Grinold, Ronald Kahn](https://amzn.to/3xMKaic) | ![](https://badgen.net/badge/reviews/46/blue) | ![](https://badgen.net/badge/rating/4/blue) |\n| [Quantitative Technical Analysis: An integrated approach to trading system development and trading management - Dr Howard B Bandy](https://www.amazon.fr/gp/product/0979183855/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0979183855&linkId=8ef7bda69477bdccf90f5ac02ee495b0) | ![](https://badgen.net/badge/reviews/37/blue) | ![](https://badgen.net/badge/rating/3.8/blue) |\n| [Advances in Active Portfolio Management: New Developments in Quantitative Investing - Richard Grinold, Ronald Kahn](https://amzn.to/3xUTK2z) | ![](https://badgen.net/badge/reviews/19/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [Professional Automated Trading: Theory and Practice - Eugene A. Durenard](https://amzn.to/3yhfOpw) | ![](https://badgen.net/badge/reviews/15/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Algorithmic Trading and Quantitative Strategies (Chapman and Hall/CRC Financial Mathematics Series) - Raja Velu, Maxence Hardy, Daniel Nehren](https://amzn.to/3xUTQXZ) | ![](https://badgen.net/badge/reviews/11/blue) | ![](https://badgen.net/badge/rating/4.2/blue) |\n| [Quantitative Trading: Algorithms, Analytics, Data, Models, Optimization - Xin Guo, Tze Leung Lai, Howard Shek, Samuel Po-Shing Wong](https://www.amazon.fr/gp/product/0367871815/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0367871815&linkId=3f2ba1cbc0e1fe02e255da740423b2fb) | ![](https://badgen.net/badge/reviews/2/blue) | ![](https://badgen.net/badge/rating/3/blue) |\n\n\n## High Frequency Trading\n\n|  Title   | Reviews | Rating |\n|----------|---------|--------|\n| [Inside the Black Box: A Simple Guide to Quantitative and High Frequency Trading - Rishi K. Narang](https://www.amazon.fr/gp/product/1118362411/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1118362411&linkId=35e02d4e636350366531a5033597a541) | ![](https://badgen.net/badge/reviews/76/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Algorithmic and High-Frequency Trading (Mathematics, Finance and Risk) - Álvaro Cartea, Sebastian Jaimungal, José Penalva](https://www.amazon.fr/gp/product/1107091144/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1107091144&linkId=64e3ceb66482d8db6827830964b85613) | ![](https://badgen.net/badge/reviews/52/blue) | ![](https://badgen.net/badge/rating/4.1/blue) |\n| [The Problem of HFT – Collected Writings on High Frequency Trading & Stock Market Structure Reform - Haim Bodek](https://www.amazon.fr/gp/product/1481978357/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1481978357&linkId=2f3acf998de645990b681e2ac9f0217c) | ![](https://badgen.net/badge/reviews/38/blue) | ![](https://badgen.net/badge/rating/4/blue) |\n| [An Introduction to High-Frequency Finance - Ramazan Gençay, Michel Dacorogna, Ulrich A. Muller, Olivier Pictet, Richard Olsen](https://www.amazon.fr/gp/product/0122796713/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0122796713&linkId=7e6c098026204f399e45d7fbb803dcca) | ![](https://badgen.net/badge/reviews/11/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [Market Microstructure in Practice - Charles-Albert Lehalle, Sophie Laruelle](https://www.amazon.fr/Market-Microstructure-Practice-Sophie-Laruelle/dp/9813231122) | ![](https://badgen.net/badge/reviews/8/blue) | ![](https://badgen.net/badge/rating/3.9/blue) |\n| [The Financial Mathematics of Market Liquidity - Olivier Gueant](https://www.amazon.com/Financial-Mathematics-Market-Liquidity-Execution/dp/1498725473) | ![](https://badgen.net/badge/reviews/6/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [High-Frequency Trading - Maureen O’Hara, David Easley, Marcos M López de Prado](https://www.amazon.fr/gp/product/178272009X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=178272009X&linkId=082f861ff6bbe4cca4ef7ccbe620a2c4) | ![](https://badgen.net/badge/reviews/1/blue) | ![](https://badgen.net/badge/rating/3/blue) |\n\n\n## Machine Learning\n\n|  Title   | Reviews | Rating |\n|----------|---------|--------|\n| [Dark Pools: The rise of A.I. trading machines and the looming threat to Wall Street - Scott Patterson](https://www.amazon.fr/gp/product/0307887189/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0307887189&linkId=2572cae24ed7de0b279580312daf0f03) | ![](https://badgen.net/badge/reviews/532/blue) | ![](https://badgen.net/badge/rating/4.5/blue) |\n| [Advances in Financial Machine Learning - Marcos Lopez de Prado](https://www.amazon.fr/gp/product/1119482089/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1119482089&linkId=7eff4d3f3d9f2d00d05032f726386e53) | ![](https://badgen.net/badge/reviews/446/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n| [Machine Learning for Algorithmic Trading: Predictive models to extract signals from market and alternative data for systematic trading strategies with Python, 2nd Edition - Stefan Jansen](https://www.amazon.fr/gp/product/1839217715/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1839217715&linkId=80e3e93e1b6027596858ed0f1fbf10c2) | ![](https://badgen.net/badge/reviews/229/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n| [Machine Learning for Asset Managers (Elements in Quantitative Finance) - Marcos M López de Prado](https://www.amazon.fr/gp/product/1108792898/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1108792898&linkId=8eb7e3c369d38b36df8dfecf05a622db) | ![](https://badgen.net/badge/reviews/96/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [Machine Learning in Finance: From Theory to Practice - Matthew F. Dixon, Igor Halperin, Paul Bilokon](https://www.amazon.fr/gp/product/3030410676/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=3030410676&linkId=5f5f1df6be62ae96ef7a0c536c3ecdb4) | ![](https://badgen.net/badge/reviews/76/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [Artificial Intelligence in Finance: A Python-Based Guide - Yves Hilpisch](https://www.amazon.fr/gp/product/1492055433/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1492055433&linkId=7c20249be4d35badb127d6a5423fc495) | ![](https://badgen.net/badge/reviews/38/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Algorithmic Trading Methods: Applications Using Advanced Statistics, Optimization, and Machine Learning Techniques - Robert Kissell](https://www.amazon.fr/gp/product/0128156309/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0128156309&linkId=0a197c0b547a0ee63ccd19389bb42edd) | ![](https://badgen.net/badge/reviews/15/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n\n\n# Videos\n\n| Title                                                              | Likes |\n|--------------------------------------------------------------------|-------|\n| [Krish Naik - Machine learning tutorials and their Application in Stock Prediction](https://www.youtube.com/watch?v=H6du_pfuznE) | ![](https://badgen.net/badge/likes/6.3k/blue) |\n| [QuantInsti Youtube - webinars about Machine Learning for trading](https://www.youtube.com/user/quantinsti/search?query=machine+learning) | ![](https://badgen.net/badge/likes/6.1k/blue) |\n| [Siraj Raval - Videos about stock market prediction using Deep Learning](https://www.youtube.com/channel/UCWN3xxRkmTPmbKwht9FuE5A/search?query=trading) | ![](https://badgen.net/badge/likes/1.7k/blue) |\n| [Quantopian - Webinars about Machine Learning for trading](https://www.youtube.com/channel/UC606MUq45P3zFLa4VGKbxsg/search?query=machine+learning) | ![](https://badgen.net/badge/likes/1.5k/blue) |\n| [Sentdex - Machine Learning for Forex and Stock analysis and algorithmic trading](https://www.youtube.com/watch?v=v_L9jR8P-54&list=PLQVvvaa0QuDe6ZBtkCNWNUbdaBo2vA4RO) | ![](https://badgen.net/badge/likes/1.5k/blue) |\n| [QuantNews - Machine Learning for Algorithmic Trading 3 part series](https://www.youtube.com/playlist?list=PLHJACfjILJ-91qkw5YC83S6COKGscctzz) | ![](https://badgen.net/badge/likes/806/blue) |\n| [Sentdex - Python programming for Finance (a few videos including Machine Learning)](https://www.youtube.com/watch?v=Z-5wNWgRJpk&index=9&list=PLQVvvaa0QuDcOdF96TBtRtuQksErCEBYZ) | ![](https://badgen.net/badge/likes/735/blue) |\n| [Chat with Traders EP042 - Machine learning for algorithmic trading with Bert Mouler](https://www.youtube.com/watch?v=i8FNO8r7PaE) | ![](https://badgen.net/badge/likes/687/blue) |\n| [Tucker Balch - Applying Deep Reinforcement Learning to Trading](https://www.youtube.com/watch?v=Pka0DC_P17k) | ![](https://badgen.net/badge/likes/487/blue) |\n| [Ernie Chan - Machine Learning for Quantitative Trading Webinar](https://www.youtube.com/watch?v=72aEDjwGMr8&t=1023s) | ![](https://badgen.net/badge/likes/436/blue) |\n| [Chat with Traders EP147 - Detective work leading to viable trading strategies with Tom Starke](https://www.youtube.com/watch?v=JjXw9Mda7eY) | ![](https://badgen.net/badge/likes/407/blue) |\n| [Chat with Traders EP142 - Algo trader using automation to bypass human flaws with Bert Mouler](https://www.youtube.com/watch?v=ofL66mh6Tw0) | ![](https://badgen.net/badge/likes/316/blue) |\n| [Master Thesis presentation, Uni of Essex - Analyzing the Limit Order Book, A Deep Learning Approach](https://www.youtube.com/watch?v=qxSh2VFmRGw) | ![](https://badgen.net/badge/likes/264/blue) |\n| [Howard Bandy - Machine Learning Trading System Development Webinar](https://www.youtube.com/watch?v=v729evhMpYk&t=1s) | ![](https://badgen.net/badge/likes/253/blue) |\n| [Chat With Traders EP131 - Trading strategies, powered by machine learning with Morgan Slade](https://www.youtube.com/watch?v=EbWbeYu8zwg) | ![](https://badgen.net/badge/likes/229/blue) |\n| [Chat with Traders Quantopian 5 - Good Uses of Machine Learning in Finance with Max Margenot](https://www.youtube.com/watch?v=Zj5sXWv9SDM) | ![](https://badgen.net/badge/likes/198/blue) |\n| [Hitoshi Harada, CTO at Alpaca - Deep Learning in Finance Talk](https://www.youtube.com/watch?v=FoQKCeDuPiY) | ![](https://badgen.net/badge/likes/147/blue) |\n| [Better System Trader EP028 - David Aronson shares research into indicators that identify Bull and Bear markets.](https://www.youtube.com/watch?v=Q4rV0Y9NokI) | ![](https://badgen.net/badge/likes/97/blue) |\n| [Prediction Machines - Deep Learning with Python in Finance Talk](https://www.youtube.com/watch?v=xvm-M-R2fZY) | ![](https://badgen.net/badge/likes/87/blue) |\n| [Better System Trader EP064 - Cryptocurrencies and Machine Learning with Bert Mouler](https://www.youtube.com/watch?v=YgRTd4nLJoU) | ![](https://badgen.net/badge/likes/35/blue) |\n| [Better System Trader EP023 - Portfolio manager Michael Himmel talks AI and machine learning in trading](https://www.youtube.com/watch?v=9tZjeyhfG0g) | ![](https://badgen.net/badge/likes/29/blue) |\n| [Better System Trader EP082 - Machine Learning With Kris Longmore](https://www.youtube.com/watch?v=0syNgsd635M) | ![](https://badgen.net/badge/likes/18/blue) |\n\n\n\n# Blogs\n\n| Title                                                              |\n|--------------------------------------------------------------------|\n| [AAA Quants, Tom Starke Blog](http://aaaquants.com/category/blog/) |\n| [AI & Systematic Trading](https://blog.paperswithbacktest.com/)          |\n| [Blackarbs blog](http://www.blackarbs.com/blog/)                   |\n| [Hardikp, Hardik Patel blog](https://www.hardikp.com/)             |\n| [Max Dama on Automated Trading](https://bit.ly/3wVZbh9)            |\n| [Medallion.Club on Systematic Trading (FR)](https://medallion.club/trading-algorithmique-quantitatif-systematique/)            |\n| [Proof Engineering: The Algorithmic Trading Platform](https://bit.ly/3lX7zYN) |\n| [Quantsportal, Jacques Joubert's Blog](http://www.quantsportal.com/blog-page/) |\n| [Quantstart - Machine Learning for Trading articles](https://www.quantstart.com/articles) |\n| [RobotWealth, Kris Longmore Blog](https://robotwealth.com/blog/) |\n\n\n# Courses\n\n| Title                                                              |\n|--------------------------------------------------------------------|\n| [AI in Finance](https://cfte.education/)                           |\n| [AI & Systematic Trading](https://paperswithbacktest.com/course)               |\n| [Algorithmic Trading for Cryptocurrencies in Python](https://github.com/tudorelu/tudorials/tree/master/trading) |\n| [Coursera, NYU - Guided Tour of Machine Learning in Finance](https://www.coursera.org/learn/guided-tour-machine-learning-finance) |\n| [Coursera, NYU - Fundamentals of Machine Learning in Finance](https://www.coursera.org/learn/fundamentals-machine-learning-in-finance) |\n| [Coursera, NYU - Reinforcement Learning in Finance](https://www.coursera.org/learn/reinforcement-learning-in-finance) |\n| [Coursera, NYU - Overview of Advanced Methods for Reinforcement Learning in Finance](https://www.coursera.org/learn/advanced-methods-reinforcement-learning-finance) |\n| [Hudson and Thames Quantitative Research](https://github.com/hudson-and-thames) |\n| [NYU: Overview of Advanced Methods of Reinforcement Learning in Finance](https://www.coursera.org/learn/advanced-methods-reinforcement-learning-finance/home/welcome) |\n| [Udacity: Artificial Intelligence for Trading](https://www.udacity.com/course/ai-for-trading--nd880) |\n| [Udacity, Georgia Tech - Machine Learning for Trading](https://www.udacity.com/course/machine-learning-for-trading--ud501) |\n"
  },
  {
    "path": "README_zh.md",
    "content": "<div align=\"center\">\n  <img src=\"static/images/awesome-systematic-trading.jpeg\" height=200 alt=\"\"/>\n  <h1>令人敬畏的系统化交易</h1>\n</div>\n<div align=center><img src=\"https://awesome.re/badge.svg\" /></div>\n\n我们正在收集一份关于寻找、开发和运行系统性交易（量化交易）策略的资源论文、软件、书籍、文章清单。\n\n<!-- omit in toc -->\n### 你在这里会发现什么？\n\n- [97个](#库和包)用于研究和实际交易的[库和包](#库和包)\n- 机构和学术界描述的[40+项战略](#战略)\n- [55本](#书籍)适合初学者和专业人士的[书籍](#书籍)\n- [23个视频](#视频)和采访\n- 还有一些[博客](#博客)和[课程](#课程)\n\n<details>\n<summary>点击这里查看完整的内容表</summary>\n\n- [库和包](#库和包)\n  - [回溯测试和真实交易](#回溯测试和真实交易)\n    - [一般 - 事件驱动框架](#一般---事件驱动框架)\n    - [一般 - 基于矢量的框架](#一般---基于矢量的框架)\n    - [加密货币](#加密货币)\n  - [交易机器人](#交易机器人)\n  - [分析](#分析)\n    - [指标](#指标)\n    - [度量衡计算](#度量衡计算)\n    - [优化](#优化)\n    - [定价](#定价)\n    - [风险](#风险)\n  - [经纪人API](#经纪人api)\n  - [数据来源](#数据来源)\n    - [一般](#一般)\n    - [加密货币](#加密货币-1)\n  - [数据科学](#数据科学)\n  - [数据库](#数据库)\n  - [图形计算](#图形计算)\n  - [机器学习](#机器学习)\n  - [时间序列分析](#时间序列分析)\n  - [视觉化](#视觉化)\n- [战略](#战略)\n  - [债券、商品、货币、股票](#债券商品货币股票)\n  - [债券、商品、股票、REITs](#债券商品股票reits)\n  - [债券、股票](#债券股票)\n  - [债券、股票、REITs](#债券股票reits)\n  - [商品](#商品)\n  - [加密货币](#加密货币-2)\n  - [货币](#货币)\n  - [股票](#股票)\n- [书籍](#书籍)\n  - [初学者](#初学者)\n  - [传记](#传记)\n  - [编码](#编码)\n  - [隐蔽性](#隐蔽性)\n  - [一般](#一般-1)\n  - [高频交易](#高频交易)\n  - [机器学习](#机器学习-1)\n- [视频](#视频)\n- [博客](#博客)\n- [课程](#课程)\n</details>\n\n<!-- omit in toc -->\n> ### 我怎样才能提供帮助？\n> 你可以通过提交带有建议的问题和在Twitter上分享来帮助。\n>\n> [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=A%20free%20and%20comprehensive%20list%20of%20papers%2C%20libraries%2C%20books%2C%20blogs%2C%20tutorials%20for%20quantitative%20traders.&url=https://github.com/paperswithbacktest/awesome-systematic-trading)\n\n\n# 库和包\n\n*97个实现交易机器人、回溯测试器、指标、定价器等的库和包列表。每个库都按其编程语言分类，并按人口降序排列（星星的数量）。*\n\n\n## 回溯测试和真实交易\n\n### 一般 - 事件驱动框架\n\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [vnpy](https://github.com/vnpy/vnpy) | 基于Python的开源量化交易系统开发框架，于2015年1月正式发布，已经一步步成长为一个全功能的量化交易平台。 | ![GitHub stars](https://badgen.net/github/stars/vnpy/vnpy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [zipline](https://github.com/quantopian/zipline) | Zipline是一个Pythonic算法交易库。它是一个事件驱动的系统，用于回溯测试。 | ![GitHub stars](https://badgen.net/github/stars/quantopian/zipline) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [backtrader](https://github.com/mementum/backtrader) | 事件驱动的Python交易策略回测库 | ![GitHub stars](https://badgen.net/github/stars/mementum/backtrader) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [QUANTAXIS](https://github.com/QUANTAXIS/QUANTAXIS) | QUANTAXIS 支持任务调度 分布式部署的 股票/期货/期权/港股/虚拟货币 数据/回测/模拟/交易/可视化/多账户 纯本地量化解决方案 | ![GitHub stars](https://badgen.net/github/stars/QUANTAXIS/QUANTAXIS) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [QuantConnect](https://github.com/QuantConnect/Lean) | QuantConnect的精益算法交易引擎（Python，C#）。 | ![GitHub stars](https://badgen.net/github/stars/QuantConnect/Lean) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Rqalpha](https://github.com/ricequant/rqalpha) | 一个可扩展、可替换的Python算法回测和交易框架，支持多种证券 | ![GitHub stars](https://badgen.net/github/stars/ricequant/rqalpha) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [finmarketpy](https://github.com/cuemacro/finmarketpy) | 用于回测交易策略和分析金融市场的Python库（前身为pythalesians）。 | ![GitHub stars](https://badgen.net/github/stars/cuemacro/finmarketpy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [backtesting.py](https://github.com/kernc/backtesting.py) | Backtesting.py是一个Python框架，用于根据历史（过去）数据推断交易策略的可行性。Backtesting.py在Backtrader的基础上进行了改进，并以各种方式超越了其他可获得的替代方案，Backtesting.py是轻量级的、快速的、用户友好的、直观的、互动的、智能的，并希望是面向未来的。 | ![GitHub stars](https://badgen.net/github/stars/kernc/backtesting.py) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [zvt](https://github.com/zvtvz/zvt) | 模块化的量化框架 | ![GitHub stars](https://badgen.net/github/stars/zvtvz/zvt) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [WonderTrader](https://github.com/wondertrader/wondertrader) | WonderTrader——量化研发交易一站式框架  | ![GitHub stars](https://badgen.net/github/stars/wondertrader/wondertrader) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [nautilus_trader](https://github.com/nautechsystems/nautilus_trader) | 一个高性能的算法交易平台和事件驱动的回测器 | ![GitHub stars](https://badgen.net/github/stars/nautechsystems/nautilus_trader) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [PandoraTrader](https://github.com/pegasusTrader/PandoraTrader) | 基于c++开发，支持多种交易API，跨平台的高频量化交易平台 | ![GitHub stars](https://badgen.net/github/stars/pegasusTrader/PandoraTrader) | ![made-with-c++](https://img.shields.io/badge/Made%20with-c++-1f425f.svg) |\n[HFTBacktest](https://github.com/nkaz001/hftbacktest) | Python+Numba 对高频交易数据进行高精度回测 | ![GitHub stars](https://badgen.net/github/stars/nkaz001/hftbacktest) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [aat](https://github.com/AsyncAlgoTrading/aat) | 一个异步的、事件驱动的框架，用于用python编写算法交易策略，并可选择用C++进行加速。它的设计是模块化和可扩展的，支持各种工具和策略，在多个交易所之间进行实时交易。 | ![GitHub stars](https://badgen.net/github/stars/AsyncAlgoTrading/aat) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [sdoosa-algo-trade-python](https://github.com/sreenivasdoosa/sdoosa-algo-trade-python) | 这个项目主要是为那些有兴趣学习使用python解释器编写自己的交易算法的algo交易新手准备的。 | ![GitHub stars](https://badgen.net/github/stars/sreenivasdoosa/sdoosa-algo-trade-python) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [lumibot](https://github.com/Lumiwealth/lumibot) | 一个非常简单而有用的回溯测试和基于样本的实时交易框架（运行速度有点慢......）。 | ![GitHub stars](https://badgen.net/github/stars/Lumiwealth/lumibot) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [quanttrader](https://github.com/letianzj/quanttrader) | 在Python中进行回测和实时交易。基于事件。类似于backtesting.py。 | ![GitHub stars](https://badgen.net/github/stars/letianzj/quanttrader) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [gobacktest](https://github.com/gobacktest/gobacktest) | 事件驱动的回溯测试框架的Go实现 | ![GitHub stars](https://badgen.net/github/stars/gobacktest/gobacktest) | ![made-with-go](https://img.shields.io/badge/Made%20with-Go-1f425f.svg) |\n| [FlashFunk](https://github.com/HFQR/FlashFunk) | Rust中的高性能运行时 | ![GitHub stars](https://badgen.net/github/stars/HFQR/FlashFunk) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n\n\n### 一般 - 基于矢量的框架\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [vectorbt](https://github.com/polakowo/vectorbt) | vectorbt采取了一种新颖的回测方法：它完全在pandas和NumPy对象上运行，并由Numba加速，以速度和规模分析任何数据。这允许在几秒钟内对成千上万的策略进行测试。 | ![GitHub stars](https://badgen.net/github/stars/polakowo/vectorbt) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [pysystemtrade](https://github.com/robcarver17/pysystemtrade) | 罗布-卡弗的《系统交易》一书中的python系统交易 | ![GitHub stars](https://badgen.net/github/stars/robcarver17/pysystemtrade) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [bt](https://github.com/pmorissette/bt) | 基于Algo和策略树的Python的灵活回测 | ![GitHub stars](https://badgen.net/github/stars/pmorissette/bt) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n### 加密货币\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [Freqtrade](https://github.com/freqtrade/freqtrade) | Freqtrade是一个用Python编写的免费和开源的加密货币交易机器人。它被设计为支持所有主要交易所，并通过Telegram进行控制。它包含回测、绘图和资金管理工具，以及通过机器学习进行策略优化。 | ![GitHub stars](https://badgen.net/github/stars/freqtrade/freqtrade) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Jesse](https://github.com/jesse-ai/jesse) | Jesse是一个先进的加密货币交易框架，旨在简化研究和定义交易策略。 | ![GitHub stars](https://badgen.net/github/stars/jesse-ai/jesse) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [OctoBot](https://github.com/Drakkar-Software/OctoBot) | 用于TA、套利和社会交易的加密货币交易机器人，具有先进的网络界面 | ![GitHub stars](https://badgen.net/github/stars/Drakkar-Software/OctoBot) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Kelp](https://github.com/stellar/kelp) | Kelp是一个免费和开源的交易机器人，适用于Stellar DEX和100多个集中式交易所 | ![GitHub stars](https://badgen.net/github/stars/stellar/kelp) | ![made-with-go](https://img.shields.io/badge/Made%20with-Go-1f425f.svg) |\n| [openlimits](https://github.com/nash-io/openlimits) | 一个Rust高性能的加密货币交易API，支持多个交易所和语言封装器。 | ![GitHub stars](https://badgen.net/github/stars/nash-io/openlimits) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n| [bTrader](https://github.com/gabriel-milan/btrader) | Binance的三角套利交易机器人 | ![GitHub stars](https://badgen.net/github/stars/gabriel-milan/btrader) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n| [crypto-crawler-rs](https://github.com/crypto-crawler/crypto-crawler-rs) | 抓取加密货币交易所的订单簿和交易信息 | ![GitHub stars](https://badgen.net/github/stars/crypto-crawler/crypto-crawler-rs) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n| [Hummingbot](https://github.com/CoinAlpha/hummingbot) | 一个用于加密货币做市的客户 | ![GitHub stars](https://badgen.net/github/stars/CoinAlpha/hummingbot) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [cryptotrader-core](https://github.com/monomadic/cryptotrader-core) | 简单的使用Rust中的加密货币交易所REST API客户端。 | ![GitHub stars](https://badgen.net/github/stars/monomadic/cryptotrader-core) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n\n## 交易机器人\n\n*交易机器人和阿尔法模型。其中一些是旧的，没有维护。*\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [Blackbird](https://github.com/butor/blackbird) | 黑鸟比特币套利：市场中立的多/空策略 | ![GitHub stars](https://badgen.net/github/stars/butor/blackbird) | ![made-with-c++](https://img.shields.io/badge/Made%20with-c++-1f425f.svg) |\n| [bitcoin-arbitrage](https://github.com/maxme/bitcoin-arbitrage) | 比特币套利 - 机会检测器 | ![GitHub stars](https://badgen.net/github/stars/maxme/bitcoin-arbitrage) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [ThetaGang](https://github.com/brndnmtthws/thetagang) | ThetaGang是一个用于收集资金的IBKR机器人 | ![GitHub stars](https://badgen.net/github/stars/brndnmtthws/thetagang) | ![made-with-typescript](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [czsc](https://github.com/waditu/czsc) | 缠中说禅技术分析工具；缠论；股票；期货；Quant；量化交易 | ![GitHub stars](https://badgen.net/github/stars/waditu/czsc) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [R2 Bitcoin Arbitrager](https://github.com/bitrinjani/r2) | R2 Bitcoin Arbitrager是一个由Node.js + TypeScript驱动的自动套利交易系统。 | ![GitHub stars](https://badgen.net/github/stars/bitrinjani/r2) | ![made-with-typescript](https://img.shields.io/badge/Made%20with-TypeScript-1f425f.svg) |\n| [analyzingalpha](https://github.com/leosmigel/analyzingalpha) | 实施简单的战略 | ![GitHub stars](https://badgen.net/github/stars/leosmigel/analyzingalpha) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [PyTrendFollow](https://github.com/chrism2671/PyTrendFollow) | PyTrendFollow - 使用趋势跟踪的系统性期货交易 | ![GitHub stars](https://badgen.net/github/stars/chrism2671/PyTrendFollow) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n## 分析\n\n### 指标\n\n*预测未来价格走势的指标库。*\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [ta-lib](https://github.com/mrjbq7/ta-lib) | 对金融市场数据进行技术分析 | ![GitHub stars](https://badgen.net/github/stars/mrjbq7/ta-lib) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [go-tart](https://github.com/iamjinlei/go-tart) | 用Go实现的[ta-lib]((https://github.com/mrjbq7/ta-lib)，支持增量更新 | ![GitHub stars](https://badgen.net/github/stars/iamjinlei/go-tart) | ![made-with-go](https://img.shields.io/badge/Made%20with-go-1f425f.svg) |\n| [pandas-ta](https://github.com/twopirllc/pandas-ta) | 潘达斯技术分析（Pandas TA）是一个易于使用的库，它利用潘达斯软件包的130多个指标和实用功能以及60多个TA Lib蜡烛图。 | ![GitHub stars](https://badgen.net/github/stars/twopirllc/pandas-ta) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [finta](https://github.com/peerchemist/finta) | 在Pandas中实施的共同财务技术指标 | ![GitHub stars](https://badgen.net/github/stars/peerchemist/finta) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [ta-rust](https://github.com/greyblake/ta-rs) | Rust语言的技术分析库 | ![GitHub stars](https://badgen.net/github/stars/greyblake/ta-rs) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n\n### 度量衡计算\n\n*财务衡量标准。*\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [quantstats](https://github.com/ranaroussi/quantstats) | 用Python编写的面向量化投资人的投资组合分析方法 | ![GitHub stars](https://badgen.net/github/stars/ranaroussi/quantstats) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [ffn](https://github.com/pmorissette/ffn) | 一个用于Python的金融函数库 | ![GitHub stars](https://badgen.net/github/stars/pmorissette/ffn) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n### 优化\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [PyPortfolioOpt](https://github.com/robertmartin8/PyPortfolioOpt) | 在python中进行金融投资组合优化，包括经典的有效边界、Black-Litterman、分级风险平价等。 | ![GitHub stars](https://badgen.net/github/stars/robertmartin8/PyPortfolioOpt) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Riskfolio-Lib](https://github.com/dcajasn/Riskfolio-Lib) | Python中的投资组合优化和定量战略资产配置 | ![GitHub stars](https://badgen.net/github/stars/dcajasn/Riskfolio-Lib) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [empyrial](https://github.com/ssantoshp/Empyrial) | Empyrial是一个基于Python的开源量化投资库，专门为金融机构和零售投资者服务，于2021年3月正式发布。 | ![GitHub stars](https://badgen.net/github/stars/ssantoshp/Empyrial) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Deepdow](https://github.com/jankrepl/deepdow) | 连接组合优化和深度学习的Python包。它的目标是促进研究在一次前进过程中进行权重分配的网络。 | ![GitHub stars](https://badgen.net/github/stars/jankrepl/deepdow) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [spectre](https://github.com/Heerozh/spectre) | Python中的投资组合优化和定量战略资产配置 | ![GitHub stars](https://badgen.net/github/stars/Heerozh/spectre) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n### 定价\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [tf-quant-finance](https://github.com/google/tf-quant-finance) | 谷歌为量化金融提供的高性能TensorFlow库 | ![GitHub stars](https://badgen.net/github/stars/google/tf-quant-finance) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [FinancePy](https://github.com/domokane/FinancePy) | 一个Python金融库，专注于金融衍生品的定价和风险管理，包括固定收益、股票、外汇和信用衍生品。 | ![GitHub stars](https://badgen.net/github/stars/domokane/FinancePy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [PyQL](https://github.com/enthought/pyql) | 著名定价库QuantLib的Python封装器 | ![GitHub stars](https://badgen.net/github/stars/enthought/pyql) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n### 风险\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [pyfolio](https://github.com/quantopian/pyfolio) | Python中的投资组合和风险分析 | ![GitHub stars](https://badgen.net/github/stars/quantopian/pyfolio) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n\n## 经纪人API\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [ccxt](https://github.com/ccxt/ccxt) | 一个JavaScript / Python / PHP加密货币交易API，支持100多个比特币/altcoin交易所 | ![GitHub stars](https://badgen.net/github/stars/ccxt/ccxt) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Ib_insync](https://github.com/erdewit/ib_insync) | 用于交互式经纪人的Python同步/async框架。 | ![GitHub stars](https://badgen.net/github/stars/erdewit/ib_insync) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Coinnect](https://github.com/hugues31/coinnect) | Coinnect是一个Rust库，旨在通过REST API提供对主要加密货币交易所的完整访问。 | ![GitHub stars](https://badgen.net/github/stars/hugues31/coinnect) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n\n\n## 数据来源\n\n### 一般\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [OpenBB Terminal](https://github.com/OpenBB-finance/OpenBBTerminal) | 为每个人、在任何地方进行投资研究。 | ![GitHub stars](https://badgen.net/github/stars/OpenBB-finance/OpenBBTerminal) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [TuShare](https://github.com/waditu/tushare) | TuShare是一个用于抓取中国股票历史数据的工具。 | ![GitHub stars](https://badgen.net/github/stars/waditu/tushare) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [yfinance](https://github.com/ranaroussi/yfinance) | yfinance提供了一个线程和Pythonic方式，从雅虎金融下载市场数据。 | ![GitHub stars](https://badgen.net/github/stars/ranaroussi/yfinance) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [AkShare](https://github.com/akfamily/akshare) | AKShare是一个优雅而简单的Python金融数据接口库，它是为人类而建的！它是为人类服务的。 | ![GitHub stars](https://badgen.net/github/stars/akfamily/akshare) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [pandas-datareader](https://github.com/pydata/pandas-datareader) | 为pandas提供最新的远程数据访问，适用于多个版本的pandas。 | ![GitHub stars](https://badgen.net/github/stars/pydata/pandas-datareader) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Quandl](https://github.com/quandl/quandl-python) | 通过一个免费的API，从数百个出版商那里获得数以百万计的金融和经济数据集。 | ![GitHub stars](https://badgen.net/github/stars/quandl/quandl-python) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [findatapy](https://github.com/cuemacro/findatapy) | findatapy创建了一个易于使用的Python API，使用统一的高级接口从许多来源下载市场数据，包括Quandl、彭博、雅虎、谷歌等。 | ![GitHub stars](https://badgen.net/github/stars/cuemacro/findatapy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Investpy](https://github.com/alvarobartt/investpy) | 用Python从Investing.com提取金融数据 | ![GitHub stars](https://badgen.net/github/stars/alvarobartt/investpy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Fundamental Analysis Data](https://github.com/JerBouma/FundamentalAnalysis) | 完整的基本面分析软件包能够收集20年的公司简介、财务报表、比率和20,000多家公司的股票数据。 | ![GitHub stars](https://badgen.net/github/stars/JerBouma/FundamentalAnalysis) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Wallstreet](https://github.com/mcdallas/wallstreet) | 华尔街。实时股票和期权工具 | ![GitHub stars](https://badgen.net/github/stars/mcdallas/wallstreet) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n\n### 加密货币\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [Cryptofeed](https://github.com/bmoscon/cryptofeed) | 使用Asyncio的加密货币交易所Websocket数据源处理程序 | ![GitHub stars](https://badgen.net/github/stars/bmoscon/cryptofeed) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Gekko-Datasets](https://github.com/xFFFFF/Gekko-Datasets) | Gekko交易机器人数据集转储。下载和使用SQLite格式的历史文件。 | ![GitHub stars](https://badgen.net/github/stars/xFFFFF/Gekko-Datasets) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [CryptoInscriber](https://github.com/Optixal/CryptoInscriber) | 一个实时的加密货币历史交易数据图谱。从任何加密货币交易所下载实时历史交易数据。 | ![GitHub stars](https://badgen.net/github/stars/Optixal/CryptoInscriber) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n[Crypto Lake](https://github.com/crypto-lake/lake-api) | 加密货币的高频订单簿和交易数据\n | ![GitHub stars](https://badgen.net/github/stars/crypto-lake/lake-api) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n## 数据科学\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [TensorFlow](https://github.com/tensorflow/tensorflow) | Python中科学计算的基本算法 | ![GitHub stars](https://badgen.net/github/stars/tensorflow/tensorflow) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Pytorch](https://github.com/pytorch/pytorch) | Python中的张量和动态神经网络具有强大的GPU加速功能 | ![GitHub stars](https://badgen.net/github/stars/pytorch/pytorch) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Keras](https://github.com/keras-team/keras) | 最具用户友好性的Python中的人类深度学习 | ![GitHub stars](https://badgen.net/github/stars/keras-team/keras) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Scikit-learn](https://github.com/scikit-learn/scikit-learn) | Python中的机器学习 | ![GitHub stars](https://badgen.net/github/stars/scikit-learn/scikit-learn) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Pandas](https://github.com/pandas-dev/pandas) | 灵活而强大的Python数据分析/操作库，提供类似于R data.frame对象的标记数据结构、统计函数以及更多。 | ![GitHub stars](https://badgen.net/github/stars/pandas-dev/pandas) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Numpy](https://github.com/numpy/numpy) | 用Python进行科学计算的基本包 | ![GitHub stars](https://badgen.net/github/stars/numpy/numpy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Scipy](https://github.com/scipy/scipy) | Python中科学计算的基本算法 | ![GitHub stars](https://badgen.net/github/stars/scipy/scipy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [PyMC](https://github.com/pymc-devs/pymc) | Python中的概率编程。用Aesara进行贝叶斯建模和概率机器学习 | ![GitHub stars](https://badgen.net/github/stars/pymc-devs/pymc) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Cvxpy](https://github.com/cvxpy/cvxpy) | 一种用于凸优化问题的Python嵌入式建模语言。 | ![GitHub stars](https://badgen.net/github/stars/cvxpy/cvxpy) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n## 数据库\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [Marketstore](https://github.com/alpacahq/marketstore) | 金融时序数据的DataFrame服务器 | ![GitHub stars](https://badgen.net/github/stars/alpacahq/marketstore) | ![made-with-go](https://img.shields.io/badge/Made%20with-Go-1f425f.svg) |\n| [Tectonicdb](https://github.com/0b01/tectonicdb) | Tectonicdb是一个快速、高度压缩的独立数据库和流媒体协议，用于订单簿上的点子。 | ![GitHub stars](https://badgen.net/github/stars/0b01/tectonicdb) | ![made-with-rust](https://img.shields.io/badge/Made%20with-Rust-1f425f.svg) |\n| [ArcticDB (Man Group)](https://github.com/man-group/arcticdb) | 用于时间序列和tick数据的高性能数据存储 | ![GitHub stars](https://badgen.net/github/stars/man-group/ArcticDB) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n## 图形计算\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [Ray](https://github.com/ray-project/ray) | 一个开源框架，为构建分布式应用提供了一个简单、通用的API。 | ![GitHub stars](https://badgen.net/github/stars/ray-project/ray) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Dask](https://github.com/dask/dask) | 在Python中使用类似Pandas的API进行任务调度的并行计算 | ![GitHub stars](https://badgen.net/github/stars/dask/dask) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Incremental (JaneStreet)](https://github.com/janestreet/incremental) | Incremental是一个库，它为你提供了一种建立复杂计算的方法，可以根据输入的变化进行有效的更新，其灵感来自Umut Acar等人关于自我调整计算的工作。Incremental在许多应用中都很有用 | ![GitHub stars](https://badgen.net/github/stars/janestreet/incremental) | ![made-with-ocaml](https://img.shields.io/badge/Made%20with-Ocaml-1f425f.svg) |\n| [Man MDF](https://github.com/man-group/mdf) | 用于Python的数据流编程工具包 | ![GitHub stars](https://badgen.net/github/stars/man-group/mdf) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [GraphKit](https://github.com/yahoo/graphkit) | 一个轻量级的Python模块，用于创建和运行计算的有序图。 | ![GitHub stars](https://badgen.net/github/stars/yahoo/graphkit) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Tributary](https://github.com/timkpaine/tributary) | 在Python中流化反应式和数据流图 | ![GitHub stars](https://badgen.net/github/stars/timkpaine/tributary) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n## 机器学习\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [QLib (Microsoft)](https://github.com/microsoft/qlib) | Qlib是一个以人工智能为导向的量化投资平台，旨在实现人工智能技术在量化投资中的潜力，授权研究，并创造价值。通过Qlib，你可以轻松尝试你的想法，创造更好的量化投资策略。越来越多的SOTA量化研究作品/论文在Qlib中发布。 | ![GitHub stars](https://badgen.net/github/stars/microsoft/qlib) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [FinRL](https://github.com/AI4Finance-Foundation/FinRL) | FinRL是第一个开源框架，展示了在量化金融中应用深度强化学习的巨大潜力。 | ![GitHub stars](https://badgen.net/github/stars/AI4Finance-Foundation/FinRL) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [MlFinLab (Hudson & Thames)](https://github.com/hudson-and-thames/mlfinlab) | MlFinLab通过提供可重复的、可解释的和易于使用的工具，帮助那些希望利用机器学习的力量的投资组合经理和交易者。 | ![GitHub stars](https://badgen.net/github/stars/hudson-and-thames/mlfinlab) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [TradingGym](https://github.com/Yvictor/TradingGym) | 交易和回测环境，用于训练强化学习代理或简单的规则基础算法。 | ![GitHub stars](https://badgen.net/github/stars/Yvictor/TradingGym) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [Stock Trading Bot using Deep Q-Learning](https://github.com/pskrunner14/trading-bot) | 使用深度Q-学习的股票交易机器人 | ![GitHub stars](https://badgen.net/github/stars/pskrunner14/trading-bot) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n## 时间序列分析\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [Facebook Prophet](https://github.com/facebook/prophet) | 对具有线性或非线性增长的多季节性的时间序列数据产生高质量的预测的工具。 | ![GitHub stars](https://badgen.net/github/stars/facebook/prophet) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [statsmodels](https://github.com/statsmodels/statsmodels) | Python模块，允许用户探索数据，估计统计模型，并进行统计测试。 | ![GitHub stars](https://badgen.net/github/stars/statsmodels/statsmodels) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [tsfresh](https://github.com/blue-yonder/tsfresh) | 从时间序列中自动提取相关特征。 | ![GitHub stars](https://badgen.net/github/stars/blue-yonder/tsfresh) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [pmdarima](https://github.com/alkaline-ml/pmdarima) | 一个统计库，旨在填补Python时间序列分析能力的空白，包括相当于R的auto.arima函数。 | ![GitHub stars](https://badgen.net/github/stars/alkaline-ml/pmdarima) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n## 视觉化\n\n| 存储库 | 描述 | 明星 | 使用方法 |\n|------------|-------------|-------|-----------|\n| [D-Tale (Man Group)](https://github.com/man-group/dtale) | D-Tale是Flask后端和React前端的结合，为你带来查看和分析Pandas数据结构的简单方法。 | ![GitHub stars](https://badgen.net/github/stars/man-group/dtale) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [mplfinance](https://github.com/matplotlib/mplfinance) | 使用Matplotlib实现金融市场数据可视化 | ![GitHub stars](https://badgen.net/github/stars/matplotlib/mplfinance) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n| [btplotting](https://github.com/happydasch/btplotting) | btplotting为回测、优化结果和backtrader的实时数据提供绘图。 | ![GitHub stars](https://badgen.net/github/stars/happydasch/btplotting) | ![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg) |\n\n\n# 战略\n\n*40+篇描述原始系统交易策略的学术论文列表。每种策略按其资产类别分类，并按夏普比率降序排列。*\n\n👉策略现在托管在 [这里](https://paperswithbacktest.com).\n\n\n上一个策略列表：\n\n## 债券、商品、货币、股票\n\n| 标题       | 夏普比率 | 挥发性 | 重新平衡 | 实施 | 来源 |\n|-------------|--------------|------------|-------------|----------------|--------|\n| 时间序列动量效应 | `0.576` | `20.5%` | `月度` | [QuantConnect](./static/strategies/time-series-momentum-effect.py) | [纸张](https://pages.stern.nyu.edu/~lpederse/papers/TimeSeriesMomentum.pdf) |\n| 利用期货进行短期反转 | `-0.05` | `12.3%` | `每周` | [QuantConnect](./static/strategies/asset-class-momentum-rotational-system.py) | [纸张](https://ideas.repec.org/a/eee/jbfina/v28y2004i6p1337-1361.html) |\n\n## 债券、商品、股票、REITs\n\n| 标题       | 夏普比率 | 挥发性 | 重新平衡 | 实施 | 来源 |\n|--------------|--------------|------------|-------------|----------------|--------|\n| 资产类别的趋势跟踪 | `0.502` | `10.4%` | `月度` | [QuantConnect](./static/strategies/asset-class-trend-following.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=962461) |\n| 动量资产配置策略 | `0.321` | `11%` | `月度` | [QuantConnect](./static/strategies/asset-class-trend-following.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1585517) |\n\n## 债券、股票\n\n| 标题       | 夏普比率 | 挥发性 | 重新平衡 | 实施 | 来源 |\n|--------------|--------------|------------|-------------|----------------|--------|\n| 成对切换 | `0.691` | `9.5%` | `季度` | [QuantConnect](./static/strategies/paired-switching.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1917044) |\n| FED模式 | `0.369` | `14.3%` | `月度` | [QuantConnect](./static/strategies/fed-model.py) | [纸张](https://www.researchgate.net/publication/228267011_The_FED_Model_and_Expected_Asset_Returns) |\n\n## 债券、股票、REITs\n\n| 标题       | 夏普比率 | 挥发性 | 重新平衡 | 实施 | 来源 |\n|--------------|--------------|------------|-------------|----------------|--------|\n| 各类资产的价值和动量因素 | `0.155` | `9.8%` | `月度` | [QuantConnect](./static/strategies/value-and-momentum-factors-across-asset-classes.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1079975) |\n\n## 商品\n\n| 标题       | 夏普比率 | 挥发性 | 重新平衡 | 实施 | 来源 |\n|--------------|--------------|------------|-------------|----------------|--------|\n| 商品中的偏度效应 | `0.482` | `17.7%` | `月度` | [QuantConnect](./static/strategies/skewness-effect-in-commodities.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2671165) |\n| 商品期货的收益不对称效应 | `0.239` | `13.4%` | `月度` | [QuantConnect](./static/strategies/return-asymmetry-effect-in-commodity-futures.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3918896) |\n| 商品的动量效应 | `0.14` | `20.3%` | `月度` | [QuantConnect](./static/strategies/momentum-effect-in-commodities.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=702281) |\n| 商品的期限结构效应 | `0.128` | `23.1%` | `月度` | [QuantConnect](./static/strategies/term-structure-effect-in-commodities.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1127213) |\n| 交易WTI/BRENT价差 | `-0.199` | `11.6%` | `每日` | [QuantConnect](./static/strategies/trading-wti-brent-spread.py) | [纸张](https://link.springer.com/article/10.1057/jdhf.2009.24) |\n\n## 加密货币\n\n| 标题       | 夏普比率 | 挥发性 | 重新平衡 | 实施 | 来源 |\n|--------------|--------------|------------|-------------|----------------|--------|\n| 比特币的隔夜季节性 | `0.892` | `20.8%` | `日内交易` | [QuantConnect](./static/strategies/intraday-seasonality-in-bitcoin.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4081000) |\n| 加密货币的再平衡溢价 | `0.698` | `27.5%` | `每日` | [QuantConnect](./static/strategies/rebalancing-premium-in-cryptocurrencies.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3982120) |\n\n## 货币\n\n| 标题       | 夏普比率 | 挥发性 | 重新平衡 | 实施 | 来源 |\n|--------------|--------------|------------|-------------|----------------|--------|\n| 外汇套利交易 | `0.254` | `7.8%` | `月度` | [QuantConnect](./static/strategies/fx-carry-trade.py) | [纸张](http://globalmarkets.db.com/new/docs/dbCurrencyReturns_March2009.pdf) |\n| 美元套利交易 | `0.113` | `5.8%` | `月度` | [QuantConnect](./static/strategies/dollar-carry-trade.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1541230) |\n| 货币动量因素 | `-0.01` | `6.7%` | `月度` | [QuantConnect](./static/strategies/currency-momentum-factor.py) | [纸张](http://globalmarkets.db.com/new/docs/dbCurrencyReturns_March2009.pdf) |\n| 货币价值因素--PPP战略 | `-0.103` | `5%` | `季度` | [QuantConnect](./static/strategies/currency-value-factor-ppp-strategy.py) | [纸张](http://globalmarkets.db.com/new/docs/dbCurrencyReturns_March2009.pdf) |\n\n## 股票\n\n| 标题       | 夏普比率 | 挥发性 | 重新平衡 | 实施 | 来源 |\n|--------------|--------------|------------|-------------|----------------|--------|\n| 资产增长效应 | `0.835` | `10.2%` | `每年一次` | [QuantConnect](./static/strategies/asset-growth-effect.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1335524) |\n| 股票的短期反转效应 | `0.816` | `21.4%` | `每周` | [QuantConnect](./static/strategies/short-term-reversal-in-stocks.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1605049) |\n| 盈利期间的逆转-公告 | `0.785` | `25.7%` | `每日` | [QuantConnect](./static/strategies/reversal-during-earnings-announcements.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2275982) |\n| 规模因素--小市值股票溢价 | `0.747` | `11.1%` | `每年一次` | [QuantConnect](./static/strategies/small-capitalization-stocks-premium-anomaly.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3177539) |\n| 股票中的低波动因素效应 | `0.717` | `11.5%` | `月度` | [QuantConnect](./static/strategies/low-volatility-factor-effect-in-stocks.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=980865) |\n| 如何使用公司文件的词汇密度 | `0.688` | `10.4%` | `月度` | [QuantConnect](./static/strategies/how-to-use-lexical-density-of-company-filings.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3921091) |\n| 波动性风险溢价效应 | `0.637` | `13.2%` | `月度` | [QuantConnect](./static/strategies/volatility-risk-premium-effect.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=189840) |\n| 与股票的配对交易 | `0.634` | `8.5%` | `每日` | [QuantConnect](./static/strategies/pairs-trading-with-stocks.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=141615) |\n| 原油预示着股票收益 | `0.599` | `11.5%` | `月度` | [QuantConnect](./static/strategies/crude-oil-predicts-equity-returns.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=460500) |\n| 对赌股票中的贝塔系数 | `0.594` | `18.9%` | `月度` | [QuantConnect](./static/strategies/betting-against-beta-factor-in-stocks.py) | [纸张](https://pages.stern.nyu.edu/~lpederse/papers/BettingAgainstBeta.pdf) |\n| 股票中的趋势跟踪效应 | `0.569` | `15.2%` | `每日` | [QuantConnect](./static/strategies/trend-following-effect-in-stocks.py) | [纸张](https://www.cis.upenn.edu/~mkearns/finread/trend.pdf) |\n| ESG因子动量策略 | `0.559` | `21.8%` | `月度` | [QuantConnect](./static/strategies/esg-factor-momentum-strategy.py) | [纸张](https://www.semanticscholar.org/paper/Can-ESG-Add-Alpha-An-Analysis-of-ESG-Tilt-and-Nagy-Kassam/64f77da4f8ce5906a73ffe4e9eec7c49c0960acc) |\n| 价值（账面价值）因素 | `0.526` | `11.9%` | `月度` | [QuantConnect](./static/strategies/value-book-to-market-factor.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2595747) |\n| 足球俱乐部的股票套利 | `0.515` | `14.2%` | `每日` | [QuantConnect](./static/strategies/soccer-clubs-stocks-arbitrage.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1343685) |\n| 合成贷款利率预示着随后的市场回报 | `0.494` | `13.7%` | `每日` | [QuantConnect](./static/strategies/synthetic-lending-rates-predict-subsequent-market-return.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3976307) |\n| 期权到期周效应 | `0.452` | `5%` | `每周` | [QuantConnect](./static/strategies/option-expiration-week-effect.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1571786) |\n| 分散交易 | `0.432` | `8.1%` | `月度` | [QuantConnect](./static/strategies/dispersion-trading.py) | [纸张](https://www.academia.edu/16327015/EQUILIBRIUM_INDEX_AND_SINGLE_STOCK_VOLATILITY_RISK_PREMIA) |\n| 共同基金回报的势头 | `0.414` | `13.6%` | `季度` | [QuantConnect](./static/strategies/momentum-in-mutual-fund-returns.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1462408) |\n| 扇形动量--旋转系统 | `0.401` | `14.1%` | `月度` | [QuantConnect](./static/strategies/sector-momentum-rotational-system.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1585517) |\n| 结合智能因素的势头和市场组合 | `0.388` | `8.2%` | `月度` | [QuantConnect](./static/strategies/combining-smart-factors-momentum-and-market-portfolio.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3745517) |\n| 股票的动量和反转与波动效应的结合 | `0.375` | `17%` | `月度` | [QuantConnect](./static/strategies/momentum-and-reversal-combined-with-volatility-effect-in-stocks.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1679464) |\n| 市场情绪和一夜之间的反常现象 | `0.369` | `3.6%` | `每日` | [QuantConnect](./static/strategies/market-sentiment-and-an-overnight-anomaly.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3829582) |\n| 一月的晴雨表 | `0.365` | `7.4%` | `月度` | [QuantConnect](./static/strategies/january-barometer.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1436516) |\n| 研发支出和股票收益 | `0.354` | `8.1%` | `每年一次` | [QuantConnect](./static/strategies/rd-expenditures-and-stock-returns.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=227564) |\n| 价值因素 - 国家内部的CAPE效应 | `0.351` | `20.2%` | `每年一次` | [QuantConnect](./static/strategies/value-factor-effect-within-countries.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2129474) |\n| 股票收益横截面的12个月周期 | `0.34` | `43.7%` | `月度` | [QuantConnect](./static/strategies/12-month-cycle-in-cross-section-of-stocks-returns.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=687022) |\n| 股票指数的月度转折 | `0.305` | `7.2%` | `每日` | [QuantConnect](./static/strategies/turn-of-the-month-in-equity-indexes.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=917884) |\n| 发薪日反常现象 | `0.269` | `3.8%` | `每日` | [QuantConnect](./static/strategies/payday-anomaly.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3257064) |\n| 利用国家ETF进行对价交易 | `0.257` | `5.7%` | `每日` | [QuantConnect](./static/strategies/pairs-trading-with-country-etfs.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1958546) |\n| 剩余动量系数 | `0.24` | `9.7%` | `月度` | [QuantConnect](./static/strategies/residual-momentum-factor.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2319861) |\n| 盈利公告溢价 | `0.192` | `3.7%` | `月度` | [QuantConnect](./static/strategies/earnings-announcement-premium.py) | [纸张](https://www.nber.org/system/files/working_papers/w13090/w13090.pdf) |\n| 股票内部的ROA效应 | `0.155` | `8.7%` | `月度` | [QuantConnect](./static/strategies/roa-effect-within-stocks.py) | [纸张](https://static1.squarespace.com/static/5e6033a4ea02d801f37e15bb/t/5f61583e88f43b7d5b7196b5/1600215105801/Chen_Zhang_JF.pdf) |\n| 股票的52周高点效应 | `0.153` | `19%` | `月度` | [QuantConnect](./static/strategies/52-weeks-high-effect-in-stocks.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1787378) |\n| 结合基本面FSCORE和股票短期逆转的情况 | `0.153` | `17.6%` | `月度` | [QuantConnect](./static/strategies/combining-fundamental-fscore-and-equity-short-term-reversals.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3097420) |\n| 对抗国际股票中的贝塔系数的赌注 | `0.142` | `9.1%` | `月度` | [QuantConnect](./static/strategies/betting-against-beta-factor-in-country-equity-indexes.py) | [纸张](https://pages.stern.nyu.edu/~lpederse/papers/BettingAgainstBeta.pdf) |\n| 一贯的动力策略 | `0.128` | `28.8%` | `6个月` | [QuantConnect](./static/strategies/consistent-momentum-strategy.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2652592) |\n| 空头利息效应--多空版本 | `0.079` | `6.6%` | `月度` | [QuantConnect](./static/strategies/short-interest-effect-long-short-version.py) | [纸张](https://www.semanticscholar.org/paper/Why-Do-Short-Interest-Levels-Predict-Stock-Returns-Boehmer-Erturk/06418ef437dc7156229532a97d0f8392373eb297?p2df) |\n| 动量因素与资产增长效应相结合 | `0.058` | `25.1%` | `月度` | [QuantConnect](./static/strategies/momentum-factor-combined-with-asset-growth-effect.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1684767) |\n| 股票中的动量因素效应 | `-0.008` | `21.8%` | `月度` | [QuantConnect](./static/strategies/momentum-factor-effect-in-stocks.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2435323) |\n| 动量因素和风格轮换效应 | `-0.056` | `10%` | `月度` | [QuantConnect](./static/strategies/momentum-factor-and-style-rotation-effect.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1276815) |\n| 盈利公告与股票回购的结合 | `-0.16` | `0.1%` | `每日` | [QuantConnect](./static/strategies/earnings-announcements-combined-with-stock-repurchases.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2589966) |\n| 盈利质量因素 | `-0.18` | `28.7%` | `每年一次` | [QuantConnect](./static/strategies/earnings-quality-factor.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2179247) |\n| 应计项目的异常情况 | `-0.272` | `13.7%` | `每年一次` | [QuantConnect](./static/strategies/accrual-anomaly.py) | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=546108) |\n| ESG、价格动量和随机优化 | `N/A` | `N/A` | `月度` |  | [纸张](https://quantpedia.com/strategies/esg-price-momentum-and-stochastic-optimization/) |\n| 公司申报和股票回报的正相似性 | `N/A` | `N/A` | `月度` |  | [纸张](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3690461) |\n\n# 书籍\n\n为量化交易者提供的55本书的综合清单。\n\n\n## 初学者\n\n|  标题   | 评论 | 评价 |\n|----------|---------|--------|\n| [A Beginner’s Guide to the Stock Market: Everything You Need to Start Making Money Today - Matthew R. Kratter](https://amzn.to/3QN2VdU) | ![](https://badgen.net/badge/reviews/14%20161/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n| [How to Day Trade for a Living: A Beginner’s Guide to Trading Tools and Tactics, Money Management, Discipline and Trading Psychology - Andrew Aziz](https://amzn.to/3bmehFv) | ![](https://badgen.net/badge/reviews/12%20278/blue) | ![](https://badgen.net/badge/rating/4.5/blue) |\n| [The Little Book of Common Sense Investing: The Only Way to Guarantee Your Fair Share of Stock Market Returns - John C. Bogle](https://amzn.to/3A4mgkR) | ![](https://badgen.net/badge/reviews/6%20969/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [Investing QuickStart Guide: The Simplified Beginner’s Guide to Successfully Navigating the Stock Market, Growing Your Wealth & Creating a Secure Financial Future - Ted D. Snow](https://amzn.to/3A5aRkX) | ![](https://badgen.net/badge/reviews/2%20537/blue) | ![](https://badgen.net/badge/rating/4.5/blue) |\n| [Day Trading QuickStart Guide: The Simplified Beginner’s Guide to Winning Trade Plans, Conquering the Markets, and Becoming a Successful Day Trader - Troy Noonan](https://amzn.to/3HPZijw) | ![](https://badgen.net/badge/reviews/1%20229/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n| [Introduction To Algo Trading: How Retail Traders Can Successfully Compete With Professional Traders - Kevin J Davey](https://amzn.to/39Tf7JC) | ![](https://badgen.net/badge/reviews/131/blue) | ![](https://badgen.net/badge/rating/4/blue) |\n| [Algorithmic Trading and DMA: An introduction to direct access trading strategies - Barry Johnson](https://amzn.to/3xYb0UN) | ![](https://badgen.net/badge/reviews/69/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n\n\n## 传记\n\n|  标题   | 评论 | 评价 |\n|----------|---------|--------|\n| [My Life as a Quant: Reflections on Physics and Finance - Emanuel Derman](https://amzn.to/3A8KudR) | ![](https://badgen.net/badge/reviews/192/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [How I Became a Quant: Insights from 25 of Wall Street’s Elite: - Barry Schachter](https://amzn.to/3Alf8kz) | ![](https://badgen.net/badge/reviews/27/blue) | ![](https://badgen.net/badge/rating/3.7/blue) |\n\n\n\n## 编码\n\n|  标题   | 评论 | 评价 |\n|----------|---------|--------|\n| [Python for Finance: Mastering Data-Driven Finance - Yves Hilpisch](https://amzn.to/3NhkTlP) | ![](https://badgen.net/badge/reviews/249/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [Trading Evolved: Anyone can Build Killer Trading Strategies in Python - Andreas F. Clenow](https://amzn.to/3A0jcGB) | ![](https://badgen.net/badge/reviews/173/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Python for Algorithmic Trading: From Idea to Cloud Deployment - Yves Hilpisch](https://amzn.to/3bpkd0C) | ![](https://badgen.net/badge/reviews/90/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n| [Algorithmic Trading with Python: Quantitative Methods and Strategy Development - Chris Conlan](https://amzn.to/3u3cxYo) | ![](https://badgen.net/badge/reviews/48/blue) | ![](https://badgen.net/badge/rating/4.2/blue) |\n| [Learn Algorithmic Trading: Build and deploy algorithmic trading systems and strategies using Python and advanced data analysis - Sebastien Donadio](https://amzn.to/3NqNghA) | ![](https://badgen.net/badge/reviews/46/blue) | ![](https://badgen.net/badge/rating/4.1/blue) |\n\n\n## 隐蔽性\n\n|  标题   | 评论 | 评价 |\n|----------|---------|--------|\n| [The Bitcoin Standard: The Decentralized Alternative to Central Banking - Saifedean Ammous](https://amzn.to/3QMJgec) | ![](https://badgen.net/badge/reviews/5%20136/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [Bitcoin Billionaires: A True Story of Genius, Betrayal, and Redemption - Ben Mezrich](https://amzn.to/39SkdWt) | ![](https://badgen.net/badge/reviews/1%20787/blue) | ![](https://badgen.net/badge/rating/4.5/blue) |\n| [Mastering Bitcoin: Programming the Open Blockchain - Andreas M. Antonopoulos](https://amzn.to/3NniZ3p) | ![](https://badgen.net/badge/reviews/955/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [Why Buy Bitcoin: Investing Today in the Money of Tomorrow - Andy Edstrom](https://amzn.to/3OMcKqZ) | ![](https://badgen.net/badge/reviews/192/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n\n\n## 一般\n\n|  标题   | 评论 | 评价 |\n|----------|---------|--------|\n| [The Intelligent Investor: The Definitive Book on Value Investing - Benjamin Graham, Jason Zweig](https://www.amazon.fr/gp/product/0060555661/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0060555661&linkId=aba73910e4e3873b6cc8364487662bd6) | ![](https://badgen.net/badge/reviews/38%20087/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [How I Invest My Money: Finance experts reveal how they save, spend, and invest - Joshua Brown, Brian Portnoy](https://amzn.to/3A4rsoU) | ![](https://badgen.net/badge/reviews/892/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Naked Forex: High-Probability Techniques for Trading Without Indicators - Alex Nekritin](https://amzn.to/3NkrAUj) | ![](https://badgen.net/badge/reviews/720/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [The Four Pillars of Investing: Lessons for Building a Winning Portfolio - William J. Bernstein](https://www.amazon.fr/gp/product/B0041842TW/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=B0041842TW&linkId=d9bc2fec4f3faa41ca4f24aed3c72122) | ![](https://badgen.net/badge/reviews/441/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [Option Volatility and Pricing: Advanced Trading Strategies and Techniques, 2nd Edition - Sheldon Natenberg](https://amzn.to/3btOxXL) | ![](https://badgen.net/badge/reviews/388/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [The Art and Science of Technical Analysis: Market Structure, Price Action, and Trading Strategies - Adam Grimes](https://www.amazon.fr/gp/product/1118115120/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1118115120&linkId=d5dc1f0e6727b2663d2186a110a31ad0) | ![](https://badgen.net/badge/reviews/305/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [The New Trading for a Living: Psychology, Discipline, Trading Tools and Systems, Risk Control, Trade Management (Wiley Trading) - Alexander Elder](https://www.amazon.fr/gp/product/1118467450/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1118467450&linkId=67ee502653bc52a5240ced9fc88eb76d) | ![](https://badgen.net/badge/reviews/242/blue) | ![](https://badgen.net/badge/rating/4.5/blue) |\n| [Building Winning Algorithmic Trading Systems: A Trader’s Journey From Data Mining to Monte Carlo Simulation to Live Trading (Wiley Trading) - Kevin J Davey](https://amzn.to/39QnsxA) | ![](https://badgen.net/badge/reviews/163/blue) | ![](https://badgen.net/badge/rating/4.2/blue) |\n| [Systematic Trading: A unique new method for designing trading and investing systems - Robert Carver](https://www.amazon.fr/gp/product/0857194453/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0857194453&linkId=32d8bffc32c01041cde066bacab76c04) | ![](https://badgen.net/badge/reviews/123/blue) | ![](https://badgen.net/badge/rating/4.2/blue) |\n| [Quantitative Momentum: A Practitioner’s Guide to Building a Momentum-Based Stock Selection System (Wiley Finance) - Wesley R. Gray, Jack R. Vogel](https://www.amazon.fr/gp/product/111923719X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=111923719X&linkId=b825cb65462a4a9254af3b7dc5328131) | ![](https://badgen.net/badge/reviews/105/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Algorithmic Trading: Winning Strategies and Their Rationale - Ernest P. Chan](https://amzn.to/3xWi8kd) | ![](https://badgen.net/badge/reviews/100/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Leveraged Trading: A professional approach to trading FX, stocks on margin, CFDs, spread bets and futures for all traders - Robert Carver](https://amzn.to/3Nhl6p7) | ![](https://badgen.net/badge/reviews/98/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n| [Trading Systems: A New Approach to System Development and Portfolio Optimisation - Emilio Tomasini, Urban Jaekle](https://www.amazon.fr/gp/product/1905641796/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1905641796&linkId=61e6634242c497498338f73641ce0a80) | ![](https://badgen.net/badge/reviews/67/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Trading and Exchanges: Market Microstructure for Practitioners - Larry Harris](https://www.amazon.fr/gp/product/0195144708/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0195144708&linkId=e47e596fc0696cbd624726cce05b4500) | ![](https://badgen.net/badge/reviews/61/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Trading Systems 2nd edition: A new approach to system development and portfolio optimisation - Emilio Tomasini, Urban Jaekle](https://www.amazon.fr/gp/product/085719755X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=085719755X&linkId=97aa558484a8dc2bf57a5296e7f38cad) | ![](https://badgen.net/badge/reviews/42/blue) | ![](https://badgen.net/badge/rating/4/blue) |\n| [Machine Trading: Deploying Computer Algorithms to Conquer the Markets - Ernest P. Chan](https://amzn.to/3OIBe4o) | ![](https://badgen.net/badge/reviews/53/blue) | ![](https://badgen.net/badge/rating/4/blue) |\n| [Quantitative Equity Portfolio Management: An Active Approach to Portfolio Construction and Management (McGraw-Hill Library of Investment and Finance) - Ludwig B Chincarini, Daehwan Kim](https://amzn.to/3yl9u0c) | ![](https://badgen.net/badge/reviews/51/blue) | ![](https://badgen.net/badge/rating/4.5/blue) |\n| [Active Portfolio Management: A Quantitative Approach for Producing Superior Returns and Controlling Risk - Richard Grinold, Ronald Kahn](https://amzn.to/3xMKaic) | ![](https://badgen.net/badge/reviews/46/blue) | ![](https://badgen.net/badge/rating/4/blue) |\n| [Quantitative Technical Analysis: An integrated approach to trading system development and trading management - Dr Howard B Bandy](https://www.amazon.fr/gp/product/0979183855/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0979183855&linkId=8ef7bda69477bdccf90f5ac02ee495b0) | ![](https://badgen.net/badge/reviews/37/blue) | ![](https://badgen.net/badge/rating/3.8/blue) |\n| [Advances in Active Portfolio Management: New Developments in Quantitative Investing - Richard Grinold, Ronald Kahn](https://amzn.to/3xUTK2z) | ![](https://badgen.net/badge/reviews/19/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n| [Professional Automated Trading: Theory and Practice - Eugene A. Durenard](https://amzn.to/3yhfOpw) | ![](https://badgen.net/badge/reviews/15/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Algorithmic Trading and Quantitative Strategies (Chapman and Hall/CRC Financial Mathematics Series) - Raja Velu, Maxence Hardy, Daniel Nehren](https://amzn.to/3xUTQXZ) | ![](https://badgen.net/badge/reviews/11/blue) | ![](https://badgen.net/badge/rating/4.2/blue) |\n| [Quantitative Trading: Algorithms, Analytics, Data, Models, Optimization - Xin Guo, Tze Leung Lai, Howard Shek, Samuel Po-Shing Wong](https://www.amazon.fr/gp/product/0367871815/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0367871815&linkId=3f2ba1cbc0e1fe02e255da740423b2fb) | ![](https://badgen.net/badge/reviews/2/blue) | ![](https://badgen.net/badge/rating/3/blue) |\n\n\n## 高频交易\n\n|  标题   | 评论 | 评价 |\n|----------|---------|--------|\n| [Inside the Black Box: A Simple Guide to Quantitative and High Frequency Trading - Rishi K. Narang](https://www.amazon.fr/gp/product/1118362411/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1118362411&linkId=35e02d4e636350366531a5033597a541) | ![](https://badgen.net/badge/reviews/76/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Algorithmic and High-Frequency Trading (Mathematics, Finance and Risk) - Álvaro Cartea, Sebastian Jaimungal, José Penalva](https://www.amazon.fr/gp/product/1107091144/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1107091144&linkId=64e3ceb66482d8db6827830964b85613) | ![](https://badgen.net/badge/reviews/52/blue) | ![](https://badgen.net/badge/rating/4.1/blue) |\n| [The Problem of HFT – Collected Writings on High Frequency Trading & Stock Market Structure Reform - Haim Bodek](https://www.amazon.fr/gp/product/1481978357/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1481978357&linkId=2f3acf998de645990b681e2ac9f0217c) | ![](https://badgen.net/badge/reviews/38/blue) | ![](https://badgen.net/badge/rating/4/blue) |\n| [An Introduction to High-Frequency Finance - Ramazan Gençay, Michel Dacorogna, Ulrich A. Muller, Olivier Pictet, Richard Olsen](https://www.amazon.fr/gp/product/0122796713/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0122796713&linkId=7e6c098026204f399e45d7fbb803dcca) | ![](https://badgen.net/badge/reviews/11/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [Market Microstructure in Practice - Charles-Albert Lehalle, Sophie Laruelle](https://www.amazon.fr/Market-Microstructure-Practice-Sophie-Laruelle/dp/9813231122) | ![](https://badgen.net/badge/reviews/8/blue) | ![](https://badgen.net/badge/rating/3.9/blue) |\n| [The Financial Mathematics of Market Liquidity - Olivier Gueant](https://www.amazon.com/Financial-Mathematics-Market-Liquidity-Execution/dp/1498725473) | ![](https://badgen.net/badge/reviews/6/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [High-Frequency Trading - Maureen O’Hara, David Easley, Marcos M López de Prado](https://www.amazon.fr/gp/product/178272009X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=178272009X&linkId=082f861ff6bbe4cca4ef7ccbe620a2c4) | ![](https://badgen.net/badge/reviews/1/blue) | ![](https://badgen.net/badge/rating/3/blue) |\n\n\n## 机器学习\n\n|  标题   | 评论 | 评价 |\n|----------|---------|--------|\n| [Dark Pools: The rise of A.I. trading machines and the looming threat to Wall Street - Scott Patterson](https://www.amazon.fr/gp/product/0307887189/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0307887189&linkId=2572cae24ed7de0b279580312daf0f03) | ![](https://badgen.net/badge/reviews/532/blue) | ![](https://badgen.net/badge/rating/4.5/blue) |\n| [Advances in Financial Machine Learning - Marcos Lopez de Prado](https://www.amazon.fr/gp/product/1119482089/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1119482089&linkId=7eff4d3f3d9f2d00d05032f726386e53) | ![](https://badgen.net/badge/reviews/446/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n| [Machine Learning for Algorithmic Trading: Predictive models to extract signals from market and alternative data for systematic trading strategies with Python, 2nd Edition - Stefan Jansen](https://www.amazon.fr/gp/product/1839217715/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1839217715&linkId=80e3e93e1b6027596858ed0f1fbf10c2) | ![](https://badgen.net/badge/reviews/229/blue) | ![](https://badgen.net/badge/rating/4.4/blue) |\n| [Machine Learning for Asset Managers (Elements in Quantitative Finance) - Marcos M López de Prado](https://www.amazon.fr/gp/product/1108792898/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1108792898&linkId=8eb7e3c369d38b36df8dfecf05a622db) | ![](https://badgen.net/badge/reviews/96/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [Machine Learning in Finance: From Theory to Practice - Matthew F. Dixon, Igor Halperin, Paul Bilokon](https://www.amazon.fr/gp/product/3030410676/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=3030410676&linkId=5f5f1df6be62ae96ef7a0c536c3ecdb4) | ![](https://badgen.net/badge/reviews/76/blue) | ![](https://badgen.net/badge/rating/4.6/blue) |\n| [Artificial Intelligence in Finance: A Python-Based Guide - Yves Hilpisch](https://www.amazon.fr/gp/product/1492055433/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=1492055433&linkId=7c20249be4d35badb127d6a5423fc495) | ![](https://badgen.net/badge/reviews/38/blue) | ![](https://badgen.net/badge/rating/4.3/blue) |\n| [Algorithmic Trading Methods: Applications Using Advanced Statistics, Optimization, and Machine Learning Techniques - Robert Kissell](https://www.amazon.fr/gp/product/0128156309/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=darchimbaud-21&creative=6746&linkCode=as2&creativeASIN=0128156309&linkId=0a197c0b547a0ee63ccd19389bb42edd) | ![](https://badgen.net/badge/reviews/15/blue) | ![](https://badgen.net/badge/rating/4.7/blue) |\n\n\n# 视频\n\n| 标题                                                              | 喜欢 |\n|--------------------------------------------------------------------|-------|\n| [Krish Naik - Machine learning tutorials and their Application in Stock Prediction](https://www.youtube.com/watch?v=H6du_pfuznE) | ![](https://badgen.net/badge/likes/6.3k/blue) |\n| [QuantInsti Youtube - webinars about Machine Learning for trading](https://www.youtube.com/user/quantinsti/search?query=machine+learning) | ![](https://badgen.net/badge/likes/6.1k/blue) |\n| [Siraj Raval - Videos about stock market prediction using Deep Learning](https://www.youtube.com/channel/UCWN3xxRkmTPmbKwht9FuE5A/search?query=trading) | ![](https://badgen.net/badge/likes/1.7k/blue) |\n| [Quantopian - Webinars about Machine Learning for trading](https://www.youtube.com/channel/UC606MUq45P3zFLa4VGKbxsg/search?query=machine+learning) | ![](https://badgen.net/badge/likes/1.5k/blue) |\n| [Sentdex - Machine Learning for Forex and Stock analysis and algorithmic trading](https://www.youtube.com/watch?v=v_L9jR8P-54&list=PLQVvvaa0QuDe6ZBtkCNWNUbdaBo2vA4RO) | ![](https://badgen.net/badge/likes/1.5k/blue) |\n| [QuantNews - Machine Learning for Algorithmic Trading 3 part series](https://www.youtube.com/playlist?list=PLHJACfjILJ-91qkw5YC83S6COKGscctzz) | ![](https://badgen.net/badge/likes/806/blue) |\n| [Sentdex - Python programming for Finance (a few videos including Machine Learning)](https://www.youtube.com/watch?v=Z-5wNWgRJpk&index=9&list=PLQVvvaa0QuDcOdF96TBtRtuQksErCEBYZ) | ![](https://badgen.net/badge/likes/735/blue) |\n| [Chat with Traders EP042 - Machine learning for algorithmic trading with Bert Mouler](https://www.youtube.com/watch?v=i8FNO8r7PaE) | ![](https://badgen.net/badge/likes/687/blue) |\n| [Tucker Balch - Applying Deep Reinforcement Learning to Trading](https://www.youtube.com/watch?v=Pka0DC_P17k) | ![](https://badgen.net/badge/likes/487/blue) |\n| [Ernie Chan - Machine Learning for Quantitative Trading Webinar](https://www.youtube.com/watch?v=72aEDjwGMr8&t=1023s) | ![](https://badgen.net/badge/likes/436/blue) |\n| [Chat with Traders EP147 - Detective work leading to viable trading strategies with Tom Starke](https://www.youtube.com/watch?v=JjXw9Mda7eY) | ![](https://badgen.net/badge/likes/407/blue) |\n| [Chat with Traders EP142 - Algo trader using automation to bypass human flaws with Bert Mouler](https://www.youtube.com/watch?v=ofL66mh6Tw0) | ![](https://badgen.net/badge/likes/316/blue) |\n| [Master Thesis presentation, Uni of Essex - Analyzing the Limit Order Book, A Deep Learning Approach](https://www.youtube.com/watch?v=qxSh2VFmRGw) | ![](https://badgen.net/badge/likes/264/blue) |\n| [Howard Bandy - Machine Learning Trading System Development Webinar](https://www.youtube.com/watch?v=v729evhMpYk&t=1s) | ![](https://badgen.net/badge/likes/253/blue) |\n| [Chat With Traders EP131 - Trading strategies, powered by machine learning with Morgan Slade](https://www.youtube.com/watch?v=EbWbeYu8zwg) | ![](https://badgen.net/badge/likes/229/blue) |\n| [Chat with Traders Quantopian 5 - Good Uses of Machine Learning in Finance with Max Margenot](https://www.youtube.com/watch?v=Zj5sXWv9SDM) | ![](https://badgen.net/badge/likes/198/blue) |\n| [Hitoshi Harada, CTO at Alpaca - Deep Learning in Finance Talk](https://www.youtube.com/watch?v=FoQKCeDuPiY) | ![](https://badgen.net/badge/likes/147/blue) |\n| [Better System Trader EP028 - David Aronson shares research into indicators that identify Bull and Bear markets.](https://www.youtube.com/watch?v=Q4rV0Y9NokI) | ![](https://badgen.net/badge/likes/97/blue) |\n| [Prediction Machines - Deep Learning with Python in Finance Talk](https://www.youtube.com/watch?v=xvm-M-R2fZY) | ![](https://badgen.net/badge/likes/87/blue) |\n| [Better System Trader EP064 - Cryptocurrencies and Machine Learning with Bert Mouler](https://www.youtube.com/watch?v=YgRTd4nLJoU) | ![](https://badgen.net/badge/likes/35/blue) |\n| [Better System Trader EP023 - Portfolio manager Michael Himmel talks AI and machine learning in trading](https://www.youtube.com/watch?v=9tZjeyhfG0g) | ![](https://badgen.net/badge/likes/29/blue) |\n| [Better System Trader EP082 - Machine Learning With Kris Longmore](https://www.youtube.com/watch?v=0syNgsd635M) | ![](https://badgen.net/badge/likes/18/blue) |\n\n\n\n# 博客\n\n| 标题                                                              |\n|--------------------------------------------------------------------|\n| [AAA Quants, Tom Starke Blog](http://aaaquants.com/category/blog/) |\n| [AI & Systematic Trading](https://blog.paperswithbacktest.com/)          |\n| [Blackarbs blog](http://www.blackarbs.com/blog/)                   |\n| [Hardikp, Hardik Patel blog](https://www.hardikp.com/)             |\n| [Max Dama on Automated Trading](https://bit.ly/3wVZbh9)            |\n| [Medallion.Club on Systematic Trading (FR)](https://medallion.club/trading-algorithmique-quantitatif-systematique/)            |\n| [Proof Engineering: The Algorithmic Trading Platform](https://bit.ly/3lX7zYN) |\n| [Quantsportal, Jacques Joubert's Blog](http://www.quantsportal.com/blog-page/) |\n| [Quantstart - Machine Learning for Trading articles](https://www.quantstart.com/articles) |\n| [RobotWealth, Kris Longmore Blog](https://robotwealth.com/blog/) |\n\n\n# 课程\n\n| 标题                                                              |\n|--------------------------------------------------------------------|\n| [AI in Finance](https://cfte.education/)                           |\n| [AI & Systematic Trading](https://paperswithbacktest.com/course)               |\n| [Algorithmic Trading for Cryptocurrencies in Python](https://github.com/tudorelu/tudorials/tree/master/trading) |\n| [Coursera, NYU - Guided Tour of Machine Learning in Finance](https://www.coursera.org/learn/guided-tour-machine-learning-finance) |\n| [Coursera, NYU - Fundamentals of Machine Learning in Finance](https://www.coursera.org/learn/fundamentals-machine-learning-in-finance) |\n| [Coursera, NYU - Reinforcement Learning in Finance](https://www.coursera.org/learn/reinforcement-learning-in-finance) |\n| [Coursera, NYU - Overview of Advanced Methods for Reinforcement Learning in Finance](https://www.coursera.org/learn/advanced-methods-reinforcement-learning-finance) |\n| [Hudson and Thames Quantitative Research](https://github.com/hudson-and-thames) |\n| [NYU: Overview of Advanced Methods of Reinforcement Learning in Finance](https://www.coursera.org/learn/advanced-methods-reinforcement-learning-finance/home/welcome) |\n| [Udacity: Artificial Intelligence for Trading](https://www.udacity.com/course/ai-for-trading--nd880) |\n| [Udacity, Georgia Tech - Machine Learning for Trading](https://www.udacity.com/course/machine-learning-for-trading--ud501) |\n"
  },
  {
    "path": "static/strategies/12-month-cycle-in-cross-section-of-stocks-returns.py",
    "content": "# https://quantpedia.com/strategies/12-month-cycle-in-cross-section-of-stocks-returns/\n#\n# The top 30% of firms based on their market cap from NYSE and AMEX are part of the investment universe. Every month, stocks are grouped \n# into ten portfolios (with an equal number of stocks in each portfolio) according to their performance in one month one year ago. Investors\n# go long in stocks from the winner decile and shorts stocks from the loser decile. The portfolio is equally weighted and rebalanced every month.\n#\n# QC implementation changes:\n#   - Universe consists of top 3000 US stock by market cap from NYSE, AMEX and NASDAQ.\n#   - Portfolio is value weighted.\n\nfrom AlgorithmImports import *\n\nclass Month12CycleinCrossSectionofStocksReturns(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)  \n        self.SetCash(100000)\n\n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        \n        self.coarse_count = 500\n        \n        # Monthly close data.\n        self.data = {}\n        self.period = 13\n        \n        self.weight = {}\n\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        \n        self.Schedule.On(self.DateRules.MonthEnd(self.symbol), self.TimeRules.BeforeMarketClose(self.symbol), self.Selection)\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(10)\n            \n    def CoarseSelectionFunction(self, coarse):\n        if not self.selection_flag:\n            return Universe.Unchanged\n\n        # Update the rolling window every month.\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            # Store monthly price.\n            if symbol in self.data:\n                self.data[symbol].update(stock.AdjustedPrice)\n\n        # selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa']\n        selected = [x.Symbol\n            for x in sorted([x for x in coarse if x.HasFundamentalData and x.Market == 'usa'],\n                key = lambda x: x.DollarVolume, reverse = True)[:self.coarse_count]]\n        \n        # Warmup price rolling windows.\n        for symbol in selected:\n            if symbol in self.data:\n                continue\n            \n            self.data[symbol] = SymbolData(symbol, self.period)\n            history = self.History(symbol, self.period*30, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet.\")\n                continue\n            closes = history.loc[symbol].close\n            \n            closes_len = len(closes.keys())\n            # Find monthly closes.\n            for index, time_close in enumerate(closes.iteritems()):\n                # index out of bounds check.\n                if index + 1 < closes_len:\n                    date_month = time_close[0].date().month\n                    next_date_month = closes.keys()[index + 1].month\n                \n                    # Found last day of month.\n                    if date_month != next_date_month:\n                        self.data[symbol].update(time_close[1])\n            \n        return [x for x in selected if self.data[x].is_ready()]    \n        \n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0 and x.CompanyReference.IsREIT != 1 and  \\\n                    ((x.SecurityReference.ExchangeId == \"NYS\") or (x.SecurityReference.ExchangeId == \"NAS\") or (x.SecurityReference.ExchangeId == \"ASE\"))]\n                    \n        if len(fine) > self.coarse_count:\n            sorted_by_market_cap = sorted(fine, key = lambda x: x.MarketCap, reverse=True)\n            top_by_market_cap = sorted_by_market_cap[:self.coarse_count]\n        else:\n            top_by_market_cap = fine\n\n        # Performance sorting. One month performance, one year ago with market cap data.\n        performance_market_cap = { x.Symbol : (self.data[x.Symbol].performance(), x.MarketCap) for x in top_by_market_cap if x.Symbol in self.data and self.data[x.Symbol].is_ready()}\n        \n        long = []\n        short = []\n        if len(performance_market_cap) >= 10:\n            sorted_by_perf = sorted(performance_market_cap.items(), key = lambda x:x[1][0], reverse = True)\n            decile = int(len(sorted_by_perf) / 10)\n            long = [x for x in sorted_by_perf[:decile]]\n            short = [x for x in sorted_by_perf[-decile:]]\n        \n        total_market_cap_long = sum([x[1][1] for x in long])\n        for symbol, perf_market_cap in long:\n            self.weight[symbol] = perf_market_cap[1] / total_market_cap_long\n\n        total_market_cap_short = sum([x[1][1] for x in short])\n        for symbol, perf_market_cap in short:\n            self.weight[symbol] = perf_market_cap[1] / total_market_cap_short\n        \n        return [x[0] for x in self.weight.items()]\n\n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n        \n        # Trade execution.\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.weight:\n                self.Liquidate(symbol)\n        \n        for symbol, w in self.weight.items():\n            self.SetHoldings(symbol, w)\n\n        self.weight.clear()\n    \n    def Selection(self):\n        self.selection_flag = True\n\nclass SymbolData():\n    def __init__(self, symbol, period):\n        self.Symbol = symbol\n        self.Window = RollingWindow[float](period)\n    \n    def update(self, value):\n        self.Window.Add(value)\n    \n    def is_ready(self):\n        return self.Window.IsReady\n        \n    # One month performance, one year ago.\n    def performance(self):\n        values = [x for x in self.Window]\n        return (values[-2] / values[-1] - 1)\n        \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/52-weeks-high-effect-in-stocks.py",
    "content": "# https://quantpedia.com/strategies/52-weeks-high-effect-in-stocks/\n#\n# The investment universe consists of all stocks from NYSE, AMEX and NASDAQ (the research paper used the CRSP \n# database for backtesting). The ratio between the current price and 52-week high is calculated for each stock \n# at the end of each month (PRILAG i,t = Price i,t / 52-Week High i,t). Every month, the investor then calculates\n# the weighted average of ratios (PRILAG i,t) from all firms in each industry (20 industries are used), where the\n# weight is the market capitalization of the stock at the end of month t. The winners (losers) are stocks in the\n# six industries with the highest (lowest) weighted averages of PRILAGi,t. The investor buys stocks in the winner\n# portfolio and shorts stocks in the loser portfolio and holds them for three months. Stocks are weighted equally\n# and the portfolio is rebalanced monthly (which means that 1/3 of the portfolio is rebalanced each month).\n#\n# QC implementation changes:\n#   - Universe consists of 500 most liquid stocks traded on NYSE, AMEX, or NASDAQ.\n\nfrom numpy import floor\nfrom AlgorithmImports import *\n\nclass Weeks52HighEffectinStocks(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x)))\n        \n        self.period = 12 * 21\n\n        # Tranching.\n        self.holding_period = 3\n        self.managed_queue = []\n\n        # Daily 'high' data.\n        self.data = {}\n        \n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        \n        self.coarse_count = 500\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(self.DateRules.MonthEnd(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Selection)\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(10)\n            \n    def CoarseSelectionFunction(self, coarse):\n        # Update the rolling window every day.\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            if symbol in self.data:\n                # Store daily price.\n                self.data[symbol].update(stock.AdjustedPrice)\n            \n        if not self.selection_flag:\n            return Universe.Unchanged\n        \n        selected = [x.Symbol\n            for x in sorted([x for x in coarse if x.HasFundamentalData and x.Market == 'usa'],\n                key = lambda x: x.DollarVolume, reverse = True)[:self.coarse_count]]\n        \n        # Warmup price rolling windows.\n        for symbol in selected:\n            if symbol in self.data:\n                continue\n            \n            self.data[symbol] = SymbolData(symbol, self.period)\n            history = self.History(symbol, self.period, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet\")\n                continue\n            closes = history.loc[symbol].close\n            for time, close in closes.iteritems():\n                self.data[symbol].update(close)\n                \n        return [x for x in selected if self.data[x].is_ready()]\n\n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0 and \\\n                ((x.SecurityReference.ExchangeId == \"NYS\") or (x.SecurityReference.ExchangeId == \"NAS\") or (x.SecurityReference.ExchangeId == \"ASE\"))]\n        \n        group = {}\n        for stock in fine:\n            symbol = stock.Symbol\n            \n            industry_group_code = stock.AssetClassification.MorningstarIndustryGroupCode\n            if industry_group_code == 0: continue\n            \n            # Adding stocks in groups.\n            if not industry_group_code in group:\n                group[industry_group_code] = []\n            \n            max_high = self.data[symbol].maximum()\n            price = self.data[symbol].get_latest_price()\n            \n            stock_prilag = (stock, price / max_high)\n            group[industry_group_code].append(stock_prilag)\n        \n        top_industries = []\n        low_industries = []\n        \n        if len(group) != 0: \n            # Weighted average of ratios calc.\n            industry_prilag_weighted_avg = {}\n            for industry_code in group:\n                total_market_cap = sum([stock_prilag_data[0].MarketCap for stock_prilag_data in group[industry_code]])\n                if total_market_cap == 0: continue\n                industry_prilag_weighted_avg[industry_code] = sum([stock_prilag_data[1] * (stock_prilag_data[0].MarketCap / total_market_cap) for stock_prilag_data in group[industry_code]])\n            \n            if len(industry_prilag_weighted_avg) != 0:\n                # Weighted average industry sorting.\n                sorted_by_weighted_avg = sorted(industry_prilag_weighted_avg.items(), key=lambda x: x[1], reverse = True)\n                top_industries = [x[0] for x in sorted_by_weighted_avg[:6]]\n                low_industries = [x[0] for x in sorted_by_weighted_avg[-6:]]\n        \n        long = []\n        short = []\n        for industry_code in top_industries:\n            for stock_prilag_data in group[industry_code]:\n                symbol = stock_prilag_data[0].Symbol\n                long.append(symbol)\n        \n        for industry_code in low_industries:\n            for stock_prilag_data in group[industry_code]:\n                symbol = stock_prilag_data[0].Symbol\n                short.append(symbol)\n                \n        long_w = self.Portfolio.TotalPortfolioValue / self.holding_period / len(long)\n        short_w = self.Portfolio.TotalPortfolioValue / self.holding_period / len(short)\n        \n        # symbol/quantity collection\n        long_symbol_q = [(x, floor(long_w / self.data[x].get_latest_price())) for x in long]\n        short_symbol_q = [(x, -floor(short_w / self.data[x].get_latest_price())) for x in short]\n        \n        self.managed_queue.append(RebalanceQueueItem(long_symbol_q + short_symbol_q))\n        \n        return long + short\n\n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n\n        remove_item = None\n        \n        # Rebalance portfolio\n        for item in self.managed_queue:\n            if item.holding_period == self.holding_period:\n                # Liquidate\n                for symbol, quantity in item.symbol_q:\n                    self.MarketOrder(symbol, -quantity)\n                remove_item = item\n            \n            # Trade execution    \n            if item.holding_period == 0:\n                open_symbol_q = []\n                \n                for symbol, quantity in item.symbol_q:\n                    if self.Securities.ContainsKey(symbol) and self.Securities[symbol].IsTradable:\n                        self.MarketOrder(symbol, quantity)\n                        open_symbol_q.append((symbol, quantity))\n                            \n                # Only opened orders will be closed        \n                item.symbol_q = open_symbol_q\n                \n            item.holding_period += 1\n            \n        # We need to remove closed part of portfolio after loop. Otherwise it will miss one item in self.managed_queue.\n        if remove_item:\n            self.managed_queue.remove(remove_item)\n\n    def Selection(self):\n        self.selection_flag = True\n\nclass RebalanceQueueItem():\n    def __init__(self, symbol_q):\n        # symbol/quantity collections\n        self.symbol_q = symbol_q  \n        self.holding_period = 0\n\nclass SymbolData():\n    def __init__(self, symbol, period):\n        self.Symbol = symbol\n        self.Price = RollingWindow[float](period)\n    \n    def update(self, value):\n        self.Price.Add(value)\n    \n    def is_ready(self):\n        return self.Price.IsReady\n     \n    def maximum(self):\n        return max([x for x in self.Price])\n        \n    def get_latest_price(self):\n        return [x for x in self.Price][0]\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/accrual-anomaly.py",
    "content": "# https://quantpedia.com/strategies/accrual-anomaly/\n#\n# The investment universe consists of all stocks on NYSE, AMEX, and NASDAQ. Balance sheet based accruals (the non-cash component of\n# earnings) are calculated as: BS_ACC = ( ∆CA – ∆Cash) – ( ∆CL – ∆STD – ∆ITP) – Dep\n# Where:\n# ∆CA = annual change in current assets\n# ∆Cash = change in cash and cash equivalents\n# ∆CL = change in current liabilities\n# ∆STD = change in debt included in current liabilities\n# ∆ITP = change in income taxes payable\n# Dep = annual depreciation and amortization expense\n# Stocks are then sorted into deciles and investor goes long stocks with the lowest accruals and short stocks with the highest accruals. \n# The portfolio is rebalanced yearly during May (after all companies publish their earnings).\n\nfrom AlgorithmImports import *\n\nclass AccrualAnomaly(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2006, 1, 1)\n        self.SetCash(100000)\n        \n        self.symbol = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n\n        self.coarse_count = 1000\n        \n        self.long = []\n        self.short = []\n        \n        # Latest accruals data.\n        self.accrual_data = {}\n        \n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(self.DateRules.MonthEnd(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Selection)\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(5)\n\n        for security in changes.RemovedSecurities:\n            symbol = security.Symbol\n            if symbol in self.accrual_data:\n                del self.accrual_data[symbol]\n                \n    def CoarseSelectionFunction(self, coarse):\n        if not self.selection_flag:\n            return Universe.Unchanged\n        \n        # selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa']\n        selected = [x.Symbol\n            for x in sorted([x for x in coarse if x.HasFundamentalData and x.Market == 'usa'],\n                key = lambda x: x.DollarVolume, reverse = True)[:self.coarse_count]]\n        \n        return selected\n    \n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if (float(x.FinancialStatements.BalanceSheet.CurrentAssets.TwelveMonths) != 0) \n                                and (float(x.FinancialStatements.BalanceSheet.CashAndCashEquivalents.TwelveMonths) != 0)\n                                and (float(x.FinancialStatements.BalanceSheet.CurrentLiabilities.TwelveMonths) != 0)\n                                and (float(x.FinancialStatements.BalanceSheet.CurrentDebt.TwelveMonths) != 0)\n                                and (float(x.FinancialStatements.BalanceSheet.IncomeTaxPayable.TwelveMonths) != 0)\n                                and (float(x.FinancialStatements.IncomeStatement.DepreciationAndAmortization.TwelveMonths) != 0)]\n\n        if len(fine) > self.coarse_count:\n            sorted_by_market_cap = sorted(fine, key = lambda x: x.MarketCap, reverse=True)\n            top_by_market_cap = sorted_by_market_cap[:self.coarse_count]\n        else:\n            top_by_market_cap = fine\n            \n        accruals = {}\n        for stock in top_by_market_cap:\n            symbol = stock.Symbol\n            \n            if symbol not in self.accrual_data:\n                self.accrual_data[symbol] = None\n                \n            # Accrual calc.\n            current_accruals_data = AccrualsData(stock.FinancialStatements.BalanceSheet.CurrentAssets.TwelveMonths, stock.FinancialStatements.BalanceSheet.CashAndCashEquivalents.TwelveMonths,\n                                                stock.FinancialStatements.BalanceSheet.CurrentLiabilities.TwelveMonths, stock.FinancialStatements.BalanceSheet.CurrentDebt.TwelveMonths, stock.FinancialStatements.BalanceSheet.IncomeTaxPayable.TwelveMonths,\n                                                stock.FinancialStatements.IncomeStatement.DepreciationAndAmortization.TwelveMonths, stock.FinancialStatements.BalanceSheet.TotalAssets.TwelveMonths)\n            \n            # There is not previous accrual data.\n            if not self.accrual_data[symbol]:\n                self.accrual_data[symbol] = current_accruals_data\n                continue\n            \n            # Accruals and market cap calc.\n            acc = self.CalculateAccruals(current_accruals_data, self.accrual_data[symbol])\n            accruals[symbol] = acc\n            \n            # Update accruals data.\n            self.accrual_data[symbol] = current_accruals_data\n        \n        # Accruals sorting.\n        sorted_by_accruals = sorted(accruals.items(), key = lambda x: x[1], reverse = True)\n        decile = int(len(sorted_by_accruals) / 10)\n        self.long = [x[0] for x in sorted_by_accruals[-decile:]]\n        self.short = [x[0] for x in sorted_by_accruals[:decile]]\n        \n        return self.long + self.short\n        \n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n        \n        # Trade execution.\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.long:\n                self.Liquidate(symbol)\n\n        for symbol in self.long:\n            self.SetHoldings(symbol, 1 / len(self.long))\n        for symbol in self.short:\n            self.SetHoldings(symbol, -1 / len(self.short))\n\n        self.long.clear()\n        self.short.clear()\n            \n    def Selection(self):\n        if self.Time.month == 4:\n            self.selection_flag = True\n            \n    def CalculateAccruals(self, current_accrual_data, prev_accrual_data):\n        delta_assets = current_accrual_data.CurrentAssets - prev_accrual_data.CurrentAssets\n        delta_cash = current_accrual_data.CashAndCashEquivalents - prev_accrual_data.CashAndCashEquivalents\n        delta_liabilities = current_accrual_data.CurrentLiabilities - prev_accrual_data.CurrentLiabilities\n        delta_debt = current_accrual_data.CurrentDebt - prev_accrual_data.CurrentDebt\n        delta_tax = current_accrual_data.IncomeTaxPayable - prev_accrual_data.IncomeTaxPayable\n        dep = current_accrual_data.DepreciationAndAmortization\n        avg_total = (current_accrual_data.TotalAssets + prev_accrual_data.TotalAssets) / 2\n        \n        bs_acc = ((delta_assets - delta_cash) - (delta_liabilities - delta_debt - delta_tax) - dep) / avg_total\n        return bs_acc\n\nclass AccrualsData():\n    def __init__(self, current_assets, cash_and_cash_equivalents, current_liabilities, current_debt, income_tax_payable, depreciation_and_amortization, total_assets):\n        self.CurrentAssets = current_assets\n        self.CashAndCashEquivalents = cash_and_cash_equivalents\n        self.CurrentLiabilities = current_liabilities\n        self.CurrentDebt = current_debt\n        self.IncomeTaxPayable = income_tax_payable\n        self.DepreciationAndAmortization = depreciation_and_amortization\n        self.TotalAssets = total_assets\n        \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/asset-class-momentum-rotational-system.py",
    "content": "# region imports\nfrom AlgorithmImports import *\n\n# endregion\n# https://quantpedia.com/strategies/asset-class-momentum-rotational-system/\n#\n# Use 5 ETFs (SPY - US stocks, EFA - foreign stocks, IEF - bonds, VNQ - REITs, GSG - commodities).\n# Pick 3 ETFs with strongest 12 month momentum into your portfolio and weight them equally.\n# Hold for 1 month and then rebalance.\n\n\nclass MomentumAssetAllocationStrategy(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.data = {}\n        period = 12 * 21\n        self.SetWarmUp(period)\n        self.symbols = [\"SPY\", \"EFA\", \"IEF\", \"VNQ\", \"GSG\"]\n\n        for symbol in self.symbols:\n            self.AddEquity(symbol, Resolution.Daily)\n            self.data[symbol] = self.ROC(symbol, period, Resolution.Daily)\n\n        self.recent_month = -1\n\n    def OnData(self, data):\n        if self.IsWarmingUp:\n            return\n\n        # monthly rebalance\n        if self.Time.month == self.recent_month:\n            return\n        self.recent_month = self.Time.month\n\n        sorted_by_momentum = sorted(\n            [\n                x\n                for x in self.data.items()\n                if x[1].IsReady and x[0] in data and data[x[0]]\n            ],\n            key=lambda x: x[1].Current.Value,\n            reverse=True,\n        )\n        count = 3\n        long = [x[0] for x in sorted_by_momentum][:count]\n\n        invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]\n        for symbol in invested:\n            if symbol not in long:\n                self.Liquidate(symbol)\n\n        for symbol in long:\n            self.SetHoldings(symbol, 1 / len(long))\n"
  },
  {
    "path": "static/strategies/asset-class-trend-following.py",
    "content": "# region imports\nfrom AlgorithmImports import *\n\n# endregion\n# https://quantpedia.com/strategies/asset-class-trend-following/\n#\n# Use 5 ETFs (SPY - US stocks, EFA - foreign stocks, IEF - bonds, VNQ - REITs,\n# GSG - commodities), equal weight the portfolio. Hold asset class ETF only when\n# it is over its 10 month Simple Moving Average, otherwise stay in cash.\n#\n# QC implementation:\n#   - SMA with period of 210 days is used.\n\n\nclass AssetClassTrendFollowing(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.sma = {}\n        period = 10 * 21\n        self.SetWarmUp(period, Resolution.Daily)\n\n        self.symbols = [\"SPY\", \"EFA\", \"IEF\", \"VNQ\", \"GSG\"]\n        self.rebalance_flag = False\n\n        self.tracked_symbol = None\n        for symbol in self.symbols:\n            self.AddEquity(symbol, Resolution.Minute)\n            self.sma[symbol] = self.SMA(symbol, period, Resolution.Daily)\n\n        self.recent_month = -1\n\n    def OnData(self, data):\n        # rebalance once a month\n        if self.Time.month == self.recent_month:\n            return\n        if self.Time.hour != 9 and self.Time.minute != 31:\n            return\n        self.recent_month = self.Time.month\n\n        long = [\n            symbol\n            for symbol in self.symbols\n            if symbol in data\n            and data[symbol]\n            and self.sma[symbol].IsReady\n            and data[symbol].Value > self.sma[symbol].Current.Value\n        ]\n\n        # trade execution\n        invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]\n        for symbol in invested:\n            if symbol not in long:\n                self.Liquidate(symbol)\n\n        for symbol in long:\n            self.SetHoldings(symbol, 1 / len(long))\n"
  },
  {
    "path": "static/strategies/asset-growth-effect.py",
    "content": "#region imports\nfrom AlgorithmImports import *\n#endregion\n# https://quantpedia.com/strategies/asset-growth-effect/\n#\n# The investment universe consists of all non-financial U.S. stocks listed on NYSE, AMEX, and NASDAQ. Stocks are then sorted each year at the end \n# of June into ten equal groups based on the percentage change in total assets for the previous year. The investor goes long decile with low asset\n# growth firms and short decile with high asset growth firms. The portfolio is weighted equally and rebalanced every year.\n#\n# QC implementation changes:\n#   - Top 3000 stocks by market cap are selected from QC stock universe.\n\nclass AssetGrowthEffect(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n        \n        self.symbol:Symbol = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n\n        self.long:list[Symbol] = []\n        self.short:list[Symbol] = []\n        \n        self.coarse_count:int = 3000\n        self.quantile:int = 10\n        \n        # Latest assets data.\n        self.total_assets:dict[Symbol, float] = {}\n        \n        self.selection_flag:bool = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(self.DateRules.MonthEnd(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Selection)\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(5)\n            \n    def CoarseSelectionFunction(self, coarse):\n        if not self.selection_flag:\n            return Universe.Unchanged\n        \n        # Select all stocks in universe.\n        return [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa']\n    \n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.FinancialStatements.BalanceSheet.TotalAssets.TwelveMonths > 0 and\n                ((x.SecurityReference.ExchangeId == \"NYS\") or (x.SecurityReference.ExchangeId == \"NAS\") or (x.SecurityReference.ExchangeId == \"ASE\"))]\n                \n        if len(fine) > self.coarse_count:\n            sorted_by_market_cap = sorted(fine, key = lambda x: x.MarketCap, reverse=True)\n            fine = sorted_by_market_cap[:self.coarse_count]\n            \n        assets_growth:dict[Symbol, float] = {}\n        for stock in fine:\n            symbol = stock.Symbol\n            \n            if symbol not in self.total_assets:\n                self.total_assets[symbol] = None\n                \n            current_assets = stock.FinancialStatements.BalanceSheet.TotalAssets.TwelveMonths\n            \n            # There is not previous assets data.\n            if not self.total_assets[symbol]:\n                self.total_assets[symbol] = current_assets\n                continue\n            \n            # Assets growth calc.\n            assets_growth[symbol] = (current_assets - self.total_assets[symbol]) / self.total_assets[symbol]\n            \n            # Update data.\n            self.total_assets[symbol] = current_assets\n        \n        # Asset growth sorting.\n        if len(assets_growth) >= self.quantile:\n            sorted_by_assets_growth = sorted(assets_growth.items(), key = lambda x: x[1], reverse = True)\n            decile = int(len(sorted_by_assets_growth) / self.quantile)\n            self.long = [x[0] for x in sorted_by_assets_growth[-decile:]]\n            self.short = [x[0] for x in sorted_by_assets_growth[:decile]]\n        \n        return self.long + self.short\n        \n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n        \n        # Trade execution.\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.long:\n                self.Liquidate(symbol)\n\n        for symbol in self.long:\n            if symbol in data and data[symbol]:\n                self.SetHoldings(symbol, 1 / len(self.long))\n\n        for symbol in self.short:\n            if symbol in data and data[symbol]:\n                self.SetHoldings(symbol, -1 / len(self.short))\n\n        self.long.clear()\n        self.short.clear()\n            \n    def Selection(self):\n        if self.Time.month == 6:\n            self.selection_flag = True\n            \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/betting-against-beta-factor-in-country-equity-indexes.py",
    "content": "# https://quantpedia.com/strategies/betting-against-beta-factor-in-country-equity-indexes/\n# \n# The investment universe consists of all country ETFs. The beta for each country is calculated with respect to the MSCI US \n# Equity Index using a 1-year rolling window. ETFs are then ranked in ascending order based on their estimated beta. The ranked \n# ETFs are assigned to one of two portfolios: low beta and high beta. Securities are weighted by the ranked betas, and the portfolios \n# are rebalanced every calendar month. Both portfolios are rescaled to have a beta of one at portfolio formation. The “Betting-Against-Beta” \n# is the zero-cost zero-beta portfolio that is long on the low-beta portfolio and that shorts the high-beta portfolio. There are a lot of \n# simple modifications (like going long on the bottom beta decile and short on the top beta decile), which could probably improve the strategy’s performance.\n\nimport numpy as np\nfrom AlgorithmImports import *\nfrom collections import deque\n\nclass BettingAgainstBetaFactorinInternationalEquities(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2002, 2, 1)\n        self.SetCash(100000)\n\n        self.countries = [\n                        \"EWA\",  # iShares MSCI Australia Index ETF\n                        \"EWO\",  # iShares MSCI Austria Investable Mkt Index ETF\n                        \"EWK\",  # iShares MSCI Belgium Investable Market Index ETF\n                        \"EWZ\",  # iShares MSCI Brazil Index ETF\n                        \"EWC\",  # iShares MSCI Canada Index ETF\n                        \"FXI\",  # iShares China Large-Cap ETF\n                        \"EWQ\",  # iShares MSCI France Index ETF\n                        \"EWG\",  # iShares MSCI Germany ETF \n                        \"EWH\",  # iShares MSCI Hong Kong Index ETF\n                        \"EWI\",  # iShares MSCI Italy Index ETF\n                        \"EWJ\",  # iShares MSCI Japan Index ETF\n                        \"EWM\",  # iShares MSCI Malaysia Index ETF\n                        \"EWW\",  # iShares MSCI Mexico Inv. Mt. Idx\n                        \"EWN\",  # iShares MSCI Netherlands Index ETF\n                        \"EWS\",  # iShares MSCI Singapore Index ETF\n                        \"EZA\",  # iShares MSCI South Africe Index ETF\n                        \"EWY\",  # iShares MSCI South Korea ETF\n                        \"EWP\",  # iShares MSCI Spain Index ETF\n                        \"EWD\",  # iShares MSCI Sweden Index ETF\n                        \"EWL\",  # iShares MSCI Switzerland Index ETF\n                        \"EWT\",  # iShares MSCI Taiwan Index ETF\n                        \"THD\",  # iShares MSCI Thailand Index ETF\n                        \"EWU\",  # iShares MSCI United Kingdom Index ETF\n            ]\n        \n        self.leverage_cap = 5\n        \n        # Daily price data.\n        self.data = {}\n        self.period = 12 * 21\n        \n        self.symbol = 'SPY'\n        \n        for symbol in self.countries + [self.symbol]:\n            data = self.AddEquity(symbol, Resolution.Daily)\n            data.SetFeeModel(CustomFeeModel())\n            data.SetLeverage(15)\n            \n            self.data[symbol] = RollingWindow[float](self.period)\n        \n        self.recent_month = -1\n\n    def OnData(self, data):\n        for symbol in self.data:\n            symbol_obj = self.Symbol(symbol)\n            if symbol_obj in data.Keys:\n                if data[symbol_obj]:\n                    price = data[symbol_obj].Value\n                    if price != 0:\n                        self.data[symbol].Add(price)\n        \n        if self.recent_month == self.Time.month:\n            return\n        self.recent_month = self.Time.month\n        \n        beta = {}\n        for symbol in self.countries:\n            # Data is ready.\n            if self.data[self.symbol].IsReady and self.data[symbol].IsReady and self.symbol in data and symbol in data:\n                market_closes = np.array([x for x in self.data[self.symbol]])\n                asset_closes = np.array([x for x in self.data[symbol]])\n                    \n                market_returns = (market_closes[1:] - market_closes[:-1]) / market_closes[:-1]\n                asset_returns = (asset_closes[1:] - asset_closes[:-1]) / asset_closes[:-1]\n                \n                cov = np.cov(asset_returns, market_returns)[0][1]\n                market_variance = np.var(market_returns)\n                beta[symbol] = cov / market_variance\n                    \n        weight = {}\n        if len(beta) != 0: \n            # Beta diff calc.\n            beta_median = np.median([x[1] for x in beta.items()])\n            \n            long_diff = [(x[0], abs(beta_median - x[1])) for x in beta.items() if x[1] < beta_median]\n            short_diff = [(x[0], abs(beta_median - x[1])) for x in beta.items() if x[1] > beta_median]\n            \n            # Beta rescale.\n            long_portfolio_beta = np.mean([beta[x[0]] for x in long_diff])\n            long_leverage = 1 / long_portfolio_beta\n\n            short_portfolio_beta = np.mean([beta[x[0]] for x in short_diff])\n            short_leverage = 1 / short_portfolio_beta\n            \n            # Cap long and short leverage.\n            long_leverage = min(self.leverage_cap, long_leverage)\n            long_leverage = max(-self.leverage_cap, long_leverage)\n            short_leverage = min(self.leverage_cap, short_leverage)\n            short_leverage = max(-self.leverage_cap, short_leverage)\n            \n            # self.Log(f\"long: {long_leverage}; short: {short_leverage}\")\n            \n            total_long_diff = sum([x[1] for x in long_diff])\n            total_short_diff = sum([x[1] for x in short_diff])\n            \n            # Beta diff weighting.\n            weight = {}\n            for symbol, diff in long_diff:\n                weight[symbol] = (diff / total_long_diff) * long_leverage\n            for symbol, diff in short_diff:\n                weight[symbol] = - (diff / total_short_diff) * short_leverage\n        \n        # Trade execution.\n        invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in invested:\n            if symbol not in weight:\n                self.Liquidate(symbol)\n        \n        for symbol, w in weight.items():\n            self.SetHoldings(symbol, w)\n                \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/betting-against-beta-factor-in-stocks.py",
    "content": "# https://quantpedia.com/strategies/betting-against-beta-factor-in-stocks/\n# \n# The investment universe consists of all stocks from the CRSP database. The beta for each stock is calculated with respect to the MSCI US Equity Index using a 1-year \n# rolling window. Stocks are then ranked in ascending order on the basis of their estimated beta. The ranked stocks are assigned to one of two portfolios: low beta and\n# high beta. Securities are weighted by the ranked betas, and portfolios are rebalanced every calendar month. Both portfolios are rescaled to have a beta of one at portfolio\n# formation. The “Betting-Against-Beta” is the zero-cost zero-beta portfolio that is long on the low-beta portfolio and short on the high-beta portfolio. There are a lot of \n# simple modifications (like going long on the bottom beta decile and short on the top beta decile), which could probably improve the strategy’s performance.\n#\n# QC implementation changes:\n#   - The investment universe consists of 1000 most liquid US stocks with price > 5$.\n\nfrom scipy import stats\nfrom AlgorithmImports import *\nimport numpy as np\n\nclass  BettingAgainstBetaFactorinStocks(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        # Daily price data.\n        self.data = {}\n        self.period = 12 * 21\n\n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        self.data[self.symbol] = RollingWindow[float](self.period)\n        \n        self.weight = {}\n        self.long = []\n        self.short = []\n        self.long_lvg = 1   # leverage for long portfolio calculated from average beta\n        self.short_lvg = 1  # leverage for short portfolio calculated from average beta\n        self.leverage_cap = 2\n        \n        self.coarse_count = 1000\n        \n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(self.DateRules.MonthStart(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Selection)\n        \n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(self.leverage_cap*3)\n            \n    def CoarseSelectionFunction(self, coarse):\n        # Update the rolling window every day.\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            if symbol in self.data:\n                # Store daily price.\n                self.data[symbol].Add(stock.AdjustedPrice)\n        \n        # Selection once a month.\n        if not self.selection_flag:\n            return Universe.Unchanged\n        \n        # selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa' and x.Price > 5]\n        selected = [x.Symbol\n            for x in sorted([x for x in coarse if x.HasFundamentalData and x.Market == 'usa' and x.Price > 5],\n                key = lambda x: x.DollarVolume, reverse = True)[:self.coarse_count]]\n                \n        # Warmup price rolling windows.\n        for symbol in selected:\n            if symbol in self.data:\n                continue\n            \n            self.data[symbol] = RollingWindow[float](self.period)\n            history = self.History(symbol, self.period, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet\")\n                continue\n            closes = history.loc[symbol].close\n            for time, close in closes.iteritems():\n                self.data[symbol].Add(close)\n                \n        return [x for x in selected if self.data[x].IsReady]\n    \n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0]\n                    \n        # if len(fine) > self.coarse_count:\n        #     sorted_by_market_cap = sorted(fine, key = lambda x: x.MarketCap, reverse=True)\n        #     top_by_market_cap = sorted_by_market_cap[:self.coarse_count]\n        # else:\n        #     top_by_market_cap = fine\n            \n        beta = {}\n        \n        if not self.data[self.symbol].IsReady: return []\n        \n        for stock in fine:\n            symbol = stock.Symbol\n            market_closes = np.array([x for x in self.data[self.symbol]])\n            stock_closes = np.array([x for x in self.data[symbol]])\n              \n            market_returns = (market_closes[:-1] - market_closes[1:]) / market_closes[1:]\n            stock_returns = (stock_closes[:-1] - stock_closes[1:]) / stock_closes[1:]\n            \n            cov = np.cov(stock_returns[::-1], market_returns[::-1])[0][1]\n            market_variance = np.var(market_returns)\n            beta[symbol] = cov / market_variance\n            \n            # beta_, intercept, r_value, p_value, std_err = stats.linregress(market_returns[::-1], stock_returns[::-1])\n            # beta[symbol] = beta_\n        \n        if len(beta) >= 10:\n            # sort by beta\n            sorted_by_beta = sorted(beta.items(), key = lambda x:x[1], reverse=True)\n            decile = int(len(sorted_by_beta) / 10)\n            self.long = [x for x in sorted_by_beta[-decile:]]\n            self.short = [x for x in sorted_by_beta[:decile]]\n            \n            # create zero-beta portfolio\n            long_mean_beta = np.mean([x[1] for x in self.long])\n            short_mean_beta = np.mean([x[1] for x in self.short])\n            \n            self.long = [x[0] for x in self.long]\n            self.short = [x[0] for x in self.short]\n            \n            self.long_lvg = 1/long_mean_beta\n            self.short_lvg = 1/short_mean_beta\n            \n            # cap leverage\n            if self.long_lvg <= 0:\n                self.long_lvg = self.leverage_cap\n            else:\n                self.long_lvg = min(self.leverage_cap, self.long_lvg)\n                \n            if self.short_lvg <= 0:\n                self.short_lvg = self.leverage_cap\n            else:\n                self.short_lvg = min(self.leverage_cap, self.short_lvg)\n        \n        return self.long + self.short\n        \n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n        \n        # Trade execution.\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.long + self.short:\n                self.Liquidate(symbol)\n        \n        long_len = len(self.long)\n        short_len = len(self.short)\n        \n        for symbol in self.long:\n            self.SetHoldings(symbol, (1/long_len)*self.long_lvg)\n        for symbol in self.short:\n            self.SetHoldings(symbol, -(1/short_len)*self.short_lvg)\n        \n        self.long.clear()\n        self.short.clear()\n        self.long_lvg = 1\n        self.short_lvg = 1\n        \n    def Selection(self):\n        self.selection_flag = True\n            \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/combining-fundamental-fscore-and-equity-short-term-reversals.py",
    "content": "from AlgorithmImports import *\n\nimport numpy as np\n\n\ndef Return(values):\n    return (values[-1] - values[0]) / values[0]\n\n\ndef Volatility(values):\n    values = np.array(values)\n    returns = (values[1:] - values[:-1]) / values[:-1]\n    return np.std(returns)\n\n\n# Custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n\n\n# Quandl free data\nclass QuandlFutures(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = \"settle\"\n\n\n# Quantpedia data\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\";\")\n\n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data[\"settle\"] = float(split[1])\n        data.Value = float(split[1])\n\n        return data\n\n\n# https://quantpedia.com/strategies/combining-fundamental-fscore-and-equity-short-term-reversals/\n#\n# The investment universe consists of common stocks (share code 10 or 11) listed in NYSE, AMEX, and NASDAQ exchanges.\n# Stocks with prices less than $5 at the end of the formation period are excluded.\n# The range of FSCORE is from zero to nine points. Each signal is equal to one (zero) point if the signal indicates a positive\n# (negative) financial performance. A firm scores one point if it has realized a positive return-on-assets (ROA), a positive\n# cash flow from operations, a positive change in ROA, a positive difference between net income from operations (Accrual),\n# a decrease in the ratio of long-term debt to total assets, a positive change in the current ratio, no-issuance of new common\n# equity, a positive change in gross margin ratio and lastly a positive change in asset turnover ratio. Firstly, construct a quarterly\n# FSCORE using the most recently available quarterly financial statement information.\nfrom AlgorithmImports import *\n\n# Monthly reversal data are matched each month with a most recently available quarterly FSCORE. The firm is classified as a fundamentally\n# strong firm if the firm’s FSCORE is greater than or equal to seven (7-9), fundamentally middle firm (4-6) and fundamentally weak firm (0-3).\n# Secondly, identify the large stocks subset – those in the top 40% of all sample stocks in terms of market capitalization\n# at the end of formation month t. After that, stocks are sorted on the past 1-month returns and firm’s most recently available quarterly FSCORE.\n# Take a long position in past losers with favorable fundamentals (7-9) and simultaneously a short position in past winners with unfavorable\n# fundamentals (0-3). The strategy is equally weighted and rebalanced monthly.\n#\n# QC implementation changes:\n#   - Instead of all listed stock, we select 500 most liquid stocks traded on NYSE, AMEX, or NASDAQ.\n\n\nclass CombiningFSCOREShortTermReversals(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.SetSecurityInitializer(\n            lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x))\n        )\n\n        self.coarse_count = 500\n\n        self.long = []\n        self.short = []\n\n        self.stock_data = {}\n        self.data = {}\n        self.period = 21\n        self.symbol = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(\n            self.DateRules.MonthEnd(self.symbol),\n            self.TimeRules.AfterMarketOpen(self.symbol),\n            self.Selection,\n        )\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(10)\n\n    def CoarseSelectionFunction(self, coarse):\n        # Update the rolling window every day.\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            # Store monthly price.\n            if symbol in self.data:\n                self.data[symbol].update(stock.AdjustedPrice)\n\n        if not self.selection_flag:\n            return Universe.Unchanged\n\n        # selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa' and x.Price > 5]\n        selected = [\n            x.Symbol\n            for x in sorted(\n                [\n                    x\n                    for x in coarse\n                    if x.HasFundamentalData and x.Market == \"usa\" and x.Price > 5\n                ],\n                key=lambda x: x.DollarVolume,\n                reverse=True,\n            )[: self.coarse_count]\n        ]\n\n        # Warmup price rolling windows.\n        for symbol in selected:\n            if symbol in self.data:\n                continue\n\n            self.data[symbol] = SymbolData(symbol, self.period)\n            history = self.History(symbol, self.period, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet.\")\n                continue\n            closes = history.loc[symbol].close\n            for time, close in closes.iteritems():\n                self.data[symbol].update(close)\n\n        return [x for x in selected if self.data[x].is_ready()]\n\n    def FineSelectionFunction(self, fine):\n        fine = [\n            x\n            for x in fine\n            if (x.EarningReports.BasicAverageShares.ThreeMonths != 0)\n            and (x.EarningReports.BasicEPS.TwelveMonths != 0)\n            and (x.ValuationRatios.PERatio != 0)\n            and (x.OperationRatios.ROA.ThreeMonths != 0)\n            and (\n                x.FinancialStatements.CashFlowStatement.CashFlowFromContinuingOperatingActivities.ThreeMonths\n                != 0\n            )\n            and (\n                x.FinancialStatements.IncomeStatement.NormalizedIncome.ThreeMonths != 0\n            )\n            and (x.FinancialStatements.BalanceSheet.LongTermDebt.ThreeMonths != 0)\n            and (x.FinancialStatements.BalanceSheet.TotalAssets.ThreeMonths != 0)\n            and (x.OperationRatios.CurrentRatio.ThreeMonths != 0)\n            and (\n                x.FinancialStatements.BalanceSheet.OrdinarySharesNumber.ThreeMonths != 0\n            )\n            and (x.OperationRatios.GrossMargin.ThreeMonths != 0)\n            and (\n                x.FinancialStatements.IncomeStatement.TotalRevenueAsReported.ThreeMonths\n                != 0\n            )\n            and (\n                (x.SecurityReference.ExchangeId == \"NYS\")\n                or (x.SecurityReference.ExchangeId == \"NAS\")\n                or (x.SecurityReference.ExchangeId == \"ASE\")\n            )\n        ]\n\n        # BM sorting\n        sorted_by_market_cap = sorted(fine, key=lambda x: x.MarketCap, reverse=True)\n        length = int((len(sorted_by_market_cap) / 100) * 40)\n        top_by_market_cap = [x for x in sorted_by_market_cap[:length]]\n\n        fine_symbols = [x.Symbol for x in top_by_market_cap]\n\n        score_performance = {}\n\n        for stock in top_by_market_cap:\n            symbol = stock.Symbol\n\n            if symbol not in self.stock_data:\n                self.stock_data[symbol] = StockData()  # Contains latest data.\n\n            roa = stock.OperationRatios.ROA.ThreeMonths\n            cfo = (\n                stock.FinancialStatements.CashFlowStatement.CashFlowFromContinuingOperatingActivities.ThreeMonths\n            )\n            leverage = (\n                stock.FinancialStatements.BalanceSheet.LongTermDebt.ThreeMonths\n                / stock.FinancialStatements.BalanceSheet.TotalAssets.ThreeMonths\n            )\n            liquidity = stock.OperationRatios.CurrentRatio.ThreeMonths\n            equity_offering = (\n                stock.FinancialStatements.BalanceSheet.OrdinarySharesNumber.ThreeMonths\n            )\n            gross_margin = stock.OperationRatios.GrossMargin.ThreeMonths\n            turnover = (\n                stock.FinancialStatements.IncomeStatement.TotalRevenueAsReported.ThreeMonths\n                / stock.FinancialStatements.BalanceSheet.TotalAssets.ThreeMonths\n            )\n\n            # Check if data has previous year's data ready.\n            stock_data = self.stock_data[symbol]\n            if (\n                (stock_data.ROA == 0)\n                or (stock_data.Leverage == 0)\n                or (stock_data.Liquidity == 0)\n                or (stock_data.Equity_offering == 0)\n                or (stock_data.Gross_margin == 0)\n                or (stock_data.Turnover == 0)\n            ):\n                stock_data.Update(\n                    roa, leverage, liquidity, equity_offering, gross_margin, turnover\n                )\n                continue\n\n            score = 0\n\n            if roa > 0:\n                score += 1\n            if cfo > 0:\n                score += 1\n            if roa > stock_data.ROA:  # ROA change is positive\n                score += 1\n            if cfo > roa:\n                score += 1\n            if leverage < stock_data.Leverage:\n                score += 1\n            if liquidity > stock_data.Liquidity:\n                score += 1\n            if equity_offering < stock_data.Equity_offering:\n                score += 1\n            if gross_margin > stock_data.Gross_margin:\n                score += 1\n            if turnover > stock_data.Turnover:\n                score += 1\n\n            score_performance[symbol] = (score, self.data[symbol].performance())\n\n            # Update new (this year's) data.\n            stock_data.Update(\n                roa, leverage, liquidity, equity_offering, gross_margin, turnover\n            )\n\n        # Clear out not updated data.\n        for symbol in self.stock_data:\n            if symbol not in fine_symbols:\n                self.stock_data[symbol] = StockData()\n\n        # Performance sorting and F score sorting.\n        self.long = [\n            x[0] for x in score_performance.items() if x[1][0] >= 7 and x[1][1] < 0\n        ]\n        self.short = [\n            x[0] for x in score_performance.items() if x[1][0] <= 3 and x[1][1] > 0\n        ]\n\n        return self.long + self.short\n\n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n\n        # Trade execution.\n        long_count = len(self.long)\n        short_count = len(self.short)\n\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.long + self.short:\n                self.Liquidate(symbol)\n\n        for symbol in self.long:\n            self.SetHoldings(symbol, 1 / long_count)\n        for symbol in self.short:\n            self.SetHoldings(symbol, -1 / short_count)\n\n        self.long.clear()\n        self.short.clear()\n\n    def Selection(self):\n        self.selection_flag = True\n\n\nclass StockData:\n    def __init__(self):\n        self.ROA = 0\n        self.Leverage = 0\n        self.Liquidity = 0\n        self.Equity_offering = 0\n        self.Gross_margin = 0\n        self.Turnover = 0\n\n    def Update(self, ROA, leverage, liquidity, eq_offering, gross_margin, turnover):\n        self.ROA = ROA\n        self.Leverage = leverage\n        self.Liquidity = liquidity\n        self.Equity_offering = eq_offering\n        self.Gross_margin = gross_margin\n        self.Turnover = turnover\n\n\nclass SymbolData:\n    def __init__(self, symbol, period):\n        self.Symbol = symbol\n        self.Price = RollingWindow[float](period)\n\n    def update(self, value):\n        self.Price.Add(value)\n\n    def is_ready(self) -> bool:\n        return self.Price.IsReady\n\n    def performance(self, values_to_skip=0) -> float:\n        closes = [x for x in self.Price][values_to_skip:]\n        return closes[0] / closes[-1] - 1\n\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n"
  },
  {
    "path": "static/strategies/combining-smart-factors-momentum-and-market-portfolio.py",
    "content": "# region imports\nfrom AlgorithmImports import *\n\n# endregion\n# https://quantpedia.com/strategies/combining-smart-factors-momentum-and-market-portfolio/\n#\n# The investment universe consists of factors from the Alpha Architect’s Factor Investing Data Library (factor for all major investment styles such as Value, Quality, Momentum, Size and Volatility)\n# based on the top 1500 US stocks. Firstly construct the fast and slow signals for each factor. The fast signal is the past one-month return, and the slow signal is the past twelve-months return.\n# For each type of signal, to obtain the weights, cross-sectionally rank signals’ based on their absolute values. The weight for the individual slow or fast signal is equal to the corresponding rank\n# divided by the sum of all ranks and multiplied by the signal’s sign (equations 3 and 4 in the paper). For the dynamically blended strategy (smart factors strategy), each factor has a final weight of\n# three-quarters of the weight of fast signal plus one-quarter of the weight of slow signal (equation 12). Nextly, consider the top 1500 US stocks as the market portfolio. The combined smart factors\n# and market strategy finds the weights of the market and factor portfolio using past moving averages of the returns. The combined strategy looks back on the past twelve months, and twelve MAs of the\n# returns. Suppose the MA for active investing (factor momentum) is larger than MA for market portfolio, then the active investing scores one point. Otherwise, the market portfolio gets one point.\n# Therefore, each month, the weight of the factor momentum and market portfolio is determined by the number of “winning” (loosing) moving averages (equations 13 and 14). The strategy is rebalanced monthly.\n#\n# QC Implementation:\n#   - IWM etf is used as 'market' portfolio.\n\nimport numpy as np\n\n\nclass CombiningSmartFactorsMomentumandMarketPortfolio(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.symbols = {\n            \"momentum\": \"US_EQUAL_DECILE_1500_12_2m_L_S\",\n            \"value\": \"US_EQUAL_DECILE_1500_B_M_L_S\",\n            \"quality\": \"US_EQUAL_DECILE_1500_ROA_L_S\",\n            \"size\": \"US_EQUAL_DECILE_1500_Size_L_S\",\n            \"volatility\": \"US_EQUAL_DECILE_1500_Volatility_L_S\",\n        }\n\n        # monthly price data\n        self.data = {}\n        self.long_period = 13\n        self.short_period = 2\n\n        self.monthly_returns = {}\n        self.monthly_returns_period = 12\n\n        for symbol, equity_symbol in self.symbols.items():\n            data = self.AddData(USEquity, equity_symbol, Resolution.Daily)\n            data.SetLeverage(10)\n            data.SetFeeModel(CustomFeeModel(self))\n            self.data[symbol] = RollingWindow[float](self.long_period)\n\n        self.market = self.AddEquity(\"IWM\", Resolution.Daily).Symbol\n        self.data[self.market] = RollingWindow[float](self.short_period)\n\n        self.monthly_returns[\"smart_factors\"] = RollingWindow[float](\n            self.monthly_returns_period\n        )\n        self.monthly_returns[\"market\"] = RollingWindow[float](\n            self.monthly_returns_period\n        )\n\n        self.selection_flag = False\n        self.Schedule.On(\n            self.DateRules.MonthStart(self.market),\n            self.TimeRules.AfterMarketOpen(self.market),\n            self.Rebalance,\n        )\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel(self))\n            security.SetLeverage(5)\n\n    def OnData(self, data):\n        # store factor monthly prices\n        for symbol, equity_symbol in self.symbols.items():\n            if equity_symbol in data and data[equity_symbol]:\n                price = data[equity_symbol].Value\n                self.data[symbol].Add(price)\n\n        # store market prices\n        if self.market in data and data[self.market]:\n            market_price = data[self.market].Value\n            self.data[self.market].Add(market_price)\n\n    def Rebalance(self):\n        slow_momentum = {}\n        fast_momentum = {}\n\n        # calculate both momentum values\n        for symbol, equity_symbol in self.symbols.items():\n            if self.data[symbol].IsReady:\n                slow_momentum[symbol] = (\n                    self.data[symbol][0] / self.data[symbol][self.long_period - 1] - 1\n                )\n                fast_momentum[symbol] = self.data[symbol][0] / self.data[symbol][1] - 1\n\n        if len(fast_momentum) != 0:\n            # momentum ranking\n            total_weight = {}\n\n            # weights\n            rank_sum = sum([x for x in range(1, len(slow_momentum) + 1)])\n            sorted_by_slow_momentum = sorted(\n                slow_momentum.items(), key=lambda x: abs(x[1]), reverse=False\n            )\n            slow_weight = {}\n            for i, (symbol, momentum) in enumerate(sorted_by_slow_momentum):\n                rank = i + 1\n                slow_weight[symbol] = (rank / rank_sum) * np.sign(momentum)\n\n            sorted_by_fast_momentum = sorted(\n                fast_momentum.items(), key=lambda x: abs(x[1]), reverse=False\n            )\n            fast_weight = {}\n            for i, (symbol, momentum) in enumerate(sorted_by_fast_momentum):\n                rank = i + 1\n                fast_weight[symbol] = (rank / rank_sum) * np.sign(momentum)\n\n            # total weight\n            for symbol, equity_symbol in self.symbols.items():\n                if symbol in slow_momentum and symbol in fast_momentum:\n                    s_weight = slow_weight[symbol]\n                    f_weight = fast_weight[symbol]\n                    total_weight[symbol] = 0.75 * f_weight + 0.25 * s_weight\n\n        # retrun calculation for market and smart factors\n        if self.data[self.market].IsReady:\n            market_return = self.data[self.market][0] / self.data[self.market][1] - 1\n            self.monthly_returns[\"market\"].Add(market_return)\n\n            # smart factor return calculation\n            smart_factors_return = 0\n            for symbol, momentum_1M in fast_momentum.items():\n                if symbol in total_weight:\n                    w = total_weight[symbol]\n                    symbol_ret = w * momentum_1M\n                    smart_factors_return += symbol_ret\n\n            if smart_factors_return != 0:\n                self.monthly_returns[\"smart_factors\"].Add(smart_factors_return)\n\n            score = {}\n            traded_weight = {}\n\n            # calculate 12 SMA's\n            if (\n                self.monthly_returns[\"smart_factors\"].IsReady\n                and self.monthly_returns[\"market\"].IsReady\n            ):\n                score[\"smart_factors\"] = 0\n                score[\"market\"] = 0\n                for sma_period in range(1, 13):\n                    factor_returns = [x for x in self.monthly_returns[\"smart_factors\"]][\n                        :sma_period\n                    ]\n                    market_returns = [x for x in self.monthly_returns[\"market\"]][\n                        :sma_period\n                    ]\n\n                    factor_mean_return = np.mean(factor_returns)\n                    market_mean_return = np.mean(market_returns)\n\n                    if factor_mean_return > market_mean_return:\n                        score[\"smart_factors\"] += 1\n                    else:\n                        score[\"market\"] += 1\n\n                total_score = score[\"market\"] + score[\"smart_factors\"]\n                if total_score != 0:\n                    traded_weight[\"market\"] = score[\"market\"] / total_score\n                    traded_weight[\"smart_factors\"] = (\n                        score[\"smart_factors\"] / total_score\n                    )\n\n                    # order execution\n                    # market\n                    self.SetHoldings(self.market, traded_weight[\"market\"])\n\n                    # smart factors\n                    for symbol, equity_symbol in self.symbols.items():\n                        if symbol in total_weight:\n                            w = total_weight[symbol]\n                            self.SetHoldings(\n                                equity_symbol, traded_weight[\"smart_factors\"] * w\n                            )\n\n\nclass USEquity(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/equity/us_ew_decile/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    # File example.\n    # date;equity\n    # 1992-01-31;0.98\n    def Reader(self, config, line, date, isLiveMode):\n        data = USEquity()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\";\")\n\n        # Prevent lookahead bias.\n        data.Time = datetime.strptime(split[0], \"%Y-%m-%d\") + timedelta(days=1)\n        data.Value = float(split[1])\n\n        return data\n\n\n# Custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n"
  },
  {
    "path": "static/strategies/consistent-momentum-strategy.py",
    "content": "# https://quantpedia.com/strategies/consistent-momentum-strategy/\n#\n# The investment universe consists of stocks listed at NYSE, AMEX, and NASDAQ, whose price data (at least for the past 7 months) are available\n# at the CRSP database. The investor creates a zero-investment portfolio at the end of the month t, longing stocks that are in the top decile \n# in terms of returns both in the period from t-7 to t-1 and from t-6 to t, while shorting stocks in the bottom decile in both periods (i.e. \n# longing consistent winners and shorting consistent losers). The stocks in the portfolio are weighted equally. The holding period is six months,\n# with no rebalancing during the period. There is a one-month skip between the formation and holding period.\n#\n# QC implementation changes:\n#   - Universe consists of 500 most liquid stocks traded on NYSE, AMEX, or NASDAQ.\n\nfrom AlgorithmImports import *\n\nclass ConsistentMomentumStrategy(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.coarse_count = 500\n        \n        self.long = []\n        self.short = []\n        \n        self.data = {}\n        \n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        \n        self.period = 7 * 21\n        \n        self.months = 0\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n\n        self.Schedule.On(self.DateRules.MonthEnd(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Rebalance)\n    \n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            symbol = security.Symbol\n            \n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(10)\n        \n    def CoarseSelectionFunction(self, coarse):\n        # Update the rolling window every day.\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            # Store monthly price.\n            if symbol in self.data:\n                self.data[symbol].update(stock.AdjustedPrice)\n\n        if not self.selection_flag:\n            return Universe.Unchanged\n        \n        # selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa']\n        selected = [x.Symbol\n            for x in sorted([x for x in coarse if x.HasFundamentalData and x.Market == 'usa'],\n                key = lambda x: x.DollarVolume, reverse = True)[:self.coarse_count]]\n        \n        # Warmup price rolling windows.\n        for symbol in selected:\n            if symbol in self.data:\n                continue\n            \n            self.data[symbol] = SymbolData(symbol, self.period)\n            history = self.History(symbol, self.period, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet\")\n                continue\n            closes = history.loc[symbol].close\n            for time, close in closes.iteritems():\n                self.data[symbol].update(close)\n                \n        return [x for x in selected if self.data[x].is_ready()]\n        \n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0 and x.CompanyReference.IsREIT != 1 and  \\\n                    ((x.SecurityReference.ExchangeId == \"NYS\") or (x.SecurityReference.ExchangeId == \"NAS\") or (x.SecurityReference.ExchangeId == \"ASE\"))]\n                    \n        # if len(fine) > self.coarse_count:\n        #     sorted_by_market_cap = sorted(fine, key = lambda x: x.MarketCap, reverse=True)\n        #     top_by_market_cap = [x.Symbol for x in sorted_by_market_cap[:self.coarse_count]]\n        # else:\n        #     top_by_market_cap = [x.Symbol for x in fine]\n        top_by_market_cap = [x.Symbol for x in fine]\n        \n        momentum_t71_t60 = { x : (self.data[x].performance_t7t1(), self.data[x].performance_t6t0()) for x in top_by_market_cap}\n        \n        # Momentum t-7 to t-1 sorting\n        sorted_by_perf_t71 = sorted(momentum_t71_t60.items(), key = lambda x: x[1][0], reverse = True)\n        decile = int(len(sorted_by_perf_t71) / 10)\n        high_by_perf_t71 = [x[0] for x in sorted_by_perf_t71[:decile]]\n        low_by_perf_t71 = [x[0] for x in sorted_by_perf_t71[-decile:]]\n\n        # Momentum t-6 to t sorting\n        sorted_by_perf_t60 = sorted(momentum_t71_t60.items(), key = lambda x: x[1][1], reverse = True)\n        decile = int(len(sorted_by_perf_t60) / 10)\n        high_by_perf_t60 = [x[0] for x in sorted_by_perf_t60[:decile]]\n        low_by_perf_t60 = [x[0] for x in sorted_by_perf_t60[-decile:]]\n        \n        self.long = [x for x in high_by_perf_t71 if x in high_by_perf_t60]\n        self.short = [x for x in low_by_perf_t71 if x in low_by_perf_t60]\n        \n        self.selection_flag = False\n        \n        return self.long + self.short\n        \n    def Rebalance(self):\n        if self.months == 0:\n            self.selection_flag = True\n            self.months += 1\n            return\n        \n        if self.months == 1:\n            # Trade execution and liquidation.\n            invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n            for symbol in invested:\n                if symbol not in self.long + self.short:\n                    self.Liquidate(symbol)\n            \n            long_count = len(self.long)\n            short_count = len(self.short)\n            \n            for symbol in self.long:\n                self.SetHoldings(symbol, 1/long_count)\n            for symbol in self.short:\n                self.SetHoldings(symbol, -1/short_count)\n        \n        self.months += 1\n        \n        if self.months == 6:\n            self.months = 0\n\nclass SymbolData():\n    def __init__(self, symbol, period):\n        self.Symbol = symbol\n        self.Price = RollingWindow[float](period)\n    \n    def update(self, value):\n        self.Price.Add(value)\n    \n    def is_ready(self):\n        return self.Price.IsReady\n        \n    def performance_t7t1(self):\n        closes = [x for x in self.Price][21:]\n        return (closes[0] / closes[-1] - 1)\n\n    def performance_t6t0(self):\n        closes = [x for x in self.Price][:-21]\n        return (closes[0] / closes[-1] - 1)\n    \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/crude-oil-predicts-equity-returns.py",
    "content": "from AlgorithmImports import *\n\nimport numpy as np\nfrom scipy.optimize import minimize\nimport statsmodels.api as sm\n\nsp100_stocks = ['AAPL','MSFT','AMZN','FB','BRKB','GOOGL','GOOG','JPM','JNJ','V','PG','XOM','UNH','BAC','MA','T','DIS','INTC','HD','VZ','MRK','PFE','CVX','KO','CMCSA','CSCO','PEP','WFC','C','BA','ADBE','WMT','CRM','MCD','MDT','BMY','ABT','NVDA','NFLX','AMGN','PM','PYPL','TMO','COST','ABBV','ACN','HON','NKE','UNP','UTX','NEE','IBM','TXN','AVGO','LLY','ORCL','LIN','SBUX','AMT','LMT','GE','MMM','DHR','QCOM','CVS','MO','LOW','FIS','AXP','BKNG','UPS','GILD','CHTR','CAT','MDLZ','GS','USB','CI','ANTM','BDX','TJX','ADP','TFC','CME','SPGI','COP','INTU','ISRG','CB','SO','D','FISV','PNC','DUK','SYK','ZTS','MS','RTN','AGN','BLK']\n\ndef MonthDiff(d1, d2):\n    return (d1.year - d2.year) * 12 + d1.month - d2.month\n\ndef Return(values):\n    return (values[-1] - values[0]) / values[0]\n    \ndef Volatility(values):\n    values = np.array(values)\n    returns = (values[1:] - values[:-1]) / values[:-1]\n    return np.std(returns)  \n\ndef MultipleLinearRegression(x, y):\n    x = np.array(x).T\n    x = sm.add_constant(x)\n    result = sm.OLS(endog=y, exog=x).fit()\n    return result\n    \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n\n# Quandl free data\nclass QuandlFutures(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = \"settle\"\n\n# Quandl \"value\" data\nclass QuandlValue(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = 'Value'\n\n# Quandl short interest data.\nclass QuandlFINRA_ShortVolume(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = 'SHORTVOLUME'    # also 'TOTALVOLUME' is accesible\n\n# Commitments of Traders data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise).\n# Data source: https://commitmentsoftraders.org/cot-data/\n# Data description: https://commitmentsoftraders.org/wp-content/uploads/Static/CoTData/file_key.html\nclass CommitmentsOfTraders(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/futures/cot/{0}.PRN\".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    # File example.\n    # DATE   OPEN     HIGH        LOW       CLOSE     VOLUME   OI\n    # ----   ----     ----        ---       -----     ------   --\n    # DATE   LARGE    SPECULATOR  COMMERCIAL HEDGER   SMALL TRADER\n    #        LONG     SHORT       LONG      SHORT     LONG     SHORT\n    def Reader(self, config, line, date, isLiveMode):\n        data = CommitmentsOfTraders()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n        split = line.split(',')\n        \n        # Prevent lookahead bias.\n        data.Time = datetime.strptime(split[0], \"%Y%m%d\") + timedelta(days=1)\n        \n        data['LARGE_SPECULATOR_LONG'] = int(split[1])\n        data['LARGE_SPECULATOR_SHORT'] = int(split[2])\n        data['COMMERCIAL_HEDGER_LONG'] = int(split[3])\n        data['COMMERCIAL_HEDGER_SHORT'] = int(split[4])\n        data['SMALL_TRADER_LONG'] = int(split[5])\n        data['SMALL_TRADER_SHORT'] = int(split[6])\n        data['open_interest'] = int(split[1]) + int(split[2]) + int(split[3]) + int(split[4]) + int(split[5]) + int(split[6])\n        data.Value = int(split[1])\n\n        return data\n\n# Quantpedia bond yield data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaIndices(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/index/{0}.csv\".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaIndices()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n        split = line.split(',')\n        \n        data.Time = datetime.strptime(split[0], \"%Y-%m-%d\") + timedelta(days=1)\n        data['close'] = float(split[1])\n        data.Value = float(split[1])\n\n        return data\n\n# Quantpedia bond yield data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaBondYield(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/bond_yield/{0}.csv\".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaBondYield()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n        split = line.split(',')\n        \n        data.Time = datetime.strptime(split[0], \"%Y-%m-%d\") + timedelta(days=1)\n        data['yield'] = float(split[1])\n        data.Value = float(split[1])\n\n        return data\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n        split = line.split(';')\n        \n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data['back_adjusted'] = float(split[1])\n        data['spliced'] = float(split[2])\n        data.Value = float(split[1])\n\n        return data\n\n# Commitments of Traders data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise).\n# Data source: https://commitmentsoftraders.org/cot-data/\n# Data description: https://commitmentsoftraders.org/wp-content/uploads/Static/CoTData/file_key.html\nclass CommitmentsOfTraders(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/futures/cot/{0}.PRN\".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    # File example.\n    # DATE   OPEN     HIGH        LOW       CLOSE     VOLUME   OI\n    # ----   ----     ----        ---       -----     ------   --\n    # DATE   LARGE    SPECULATOR  COMMERCIAL HEDGER   SMALL TRADER\n    #        LONG     SHORT       LONG      SHORT     LONG     SHORT\n    def Reader(self, config, line, date, isLiveMode):\n        data = CommitmentsOfTraders()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n        split = line.split(',')\n        \n        # Prevent lookahead bias.\n        data.Time = datetime.strptime(split[0], \"%Y%m%d\") + timedelta(days=1)\n        \n        data['LARGE_SPECULATOR_LONG'] = int(split[1])\n        data['LARGE_SPECULATOR_SHORT'] = int(split[2])\n        data['COMMERCIAL_HEDGER_LONG'] = int(split[3])\n        data['COMMERCIAL_HEDGER_SHORT'] = int(split[4])\n        data['SMALL_TRADER_LONG'] = int(split[5])\n        data['SMALL_TRADER_SHORT'] = int(split[6])\n\n        data.Value = int(split[1])\n\n        return data\n        \n# NOTE: Manager for new trades. It's represented by certain count of equally weighted brackets for long and short positions.\n# If there's a place for new trade, it will be managed for time of holding period.\nclass TradeManager():\n    def __init__(self, algorithm, long_size, short_size, holding_period):\n        self.algorithm = algorithm  # algorithm to execute orders in.\n        \n        self.long_size = long_size\n        self.short_size = short_size\n        \n        self.long_len = 0\n        self.short_len = 0\n    \n        # Arrays of ManagedSymbols\n        self.symbols = []\n        \n        self.holding_period = holding_period    # Days of holding.\n    \n    # Add stock symbol object\n    def Add(self, symbol, long_flag):\n        # Open new long trade.\n        managed_symbol = ManagedSymbol(symbol, self.holding_period, long_flag)\n        \n        if long_flag:\n            # If there's a place for it.\n            if self.long_len < self.long_size:\n                self.symbols.append(managed_symbol)\n                self.algorithm.SetHoldings(symbol, 1 / self.long_size)\n                self.long_len += 1\n            else:\n                self.algorithm.Log(\"There's not place for additional trade.\")\n\n        # Open new short trade.\n        else:\n            # If there's a place for it.\n            if self.short_len < self.short_size:\n                self.symbols.append(managed_symbol)\n                self.algorithm.SetHoldings(symbol, - 1 / self.short_size)\n                self.short_len += 1\n            else:\n                self.algorithm.Log(\"There's not place for additional trade.\")\n   \n    # Decrement holding period and liquidate symbols.\n    def TryLiquidate(self):\n        symbols_to_delete = []\n        for managed_symbol in self.symbols:\n            managed_symbol.days_to_liquidate -= 1\n            \n            # Liquidate.\n            if managed_symbol.days_to_liquidate == 0:\n                symbols_to_delete.append(managed_symbol)\n                self.algorithm.Liquidate(managed_symbol.symbol)\n                \n                if managed_symbol.long_flag: self.long_len -= 1\n                else: self.short_len -= 1\n\n        # Remove symbols from management.\n        for managed_symbol in symbols_to_delete:\n            self.symbols.remove(managed_symbol)\n    \n    def LiquidateTicker(self, ticker):\n        symbol_to_delete = None\n        for managed_symbol in self.symbols:\n            if managed_symbol.symbol.Value == ticker:\n                self.algorithm.Liquidate(managed_symbol.symbol)\n                symbol_to_delete = managed_symbol\n                if managed_symbol.long_flag: self.long_len -= 1\n                else: self.short_len -= 1\n                \n                break\n        \n        if symbol_to_delete: self.symbols.remove(symbol_to_delete)\n        else: self.algorithm.Debug(\"Ticker is not held in portfolio!\")\n    \nclass ManagedSymbol():\n    def __init__(self, symbol, days_to_liquidate, long_flag):\n        self.symbol = symbol\n        self.days_to_liquidate = days_to_liquidate\n        self.long_flag = long_flag\n        \nclass PortfolioOptimization(object):\n    def __init__(self, df_return, risk_free_rate, num_assets):\n        self.daily_return = df_return\n        self.risk_free_rate = risk_free_rate\n        self.n = num_assets # numbers of risk assets in portfolio\n        self.target_vol = 0.05\n\n    def annual_port_return(self, weights):\n        # calculate the annual return of portfolio\n        return np.sum(self.daily_return.mean() * weights) * 252\n\n    def annual_port_vol(self, weights):\n        # calculate the annual volatility of portfolio\n        return np.sqrt(np.dot(weights.T, np.dot(self.daily_return.cov() * 252, weights)))\n\n    def min_func(self, weights):\n        # method 1: maximize sharp ratio\n        return - self.annual_port_return(weights) / self.annual_port_vol(weights)\n        \n        # method 2: maximize the return with target volatility\n        #return - self.annual_port_return(weights) / self.target_vol\n\n    def opt_portfolio(self):\n        # maximize the sharpe ratio to find the optimal weights\n        cons = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})\n        bnds = tuple((0, 1) for x in range(2)) + tuple((0, 0.25) for x in range(self.n - 2))\n        opt = minimize(self.min_func,                               # object function\n                       np.array(self.n * [1. / self.n]),            # initial value\n                       method='SLSQP',                              # optimization method\n                       bounds=bnds,                                 # bounds for variables \n                       constraints=cons)                            # constraint conditions\n                      \n        opt_weights = opt['x']\n \n        return opt_weights\n\n\n# https://quantpedia.com/strategies/crude-oil-predicts-equity-returns/\n#\n# Several types of oil can be used (Brent, WTI, Dubai etc.) without big differences in results. The source paper for\n# this anomaly uses Arab Light crude oil. Monthly oil returns are used in the regression equation as an independent\n# variable and equity returns are used as a dependent variable. The model is re-estimated every month and\n# observations of the last month are added. The investor determines whether the expected stock market return in \n# a specific month (based on regression results and conditional on the oil price change in the previous month) is higher\n# or lower than the risk-free rate. The investor is fully invested in the market portfolio if the expected\n# return is higher (bull market); he invests in cash if the expected return is lower (bear market).\n\nfrom data_tools import QuantpediaFutures, QuandlValue, CustomFeeModel\nfrom AlgorithmImports import *\nimport numpy as np\nfrom collections import deque\nfrom scipy import stats\n\nclass CrudeOilPredictsEquityReturns(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.data = {}\n\n        self.symbols = [\n            \"CME_ES1\",  # E-mini S&P 500 Futures, Continuous Contract #1\n            \"CME_CL1\"   # Crude Oil Futures, Continuous Contract #1\n        ]\n        \n        self.cash = self.AddEquity('SHY', Resolution.Daily).Symbol\n        \n        self.risk_free_rate = self.AddData(QuandlValue, 'FRED/DGS3MO', Resolution.Daily).Symbol\n        \n        # Monhtly price data.\n        self.data = {}\n        \n        for symbol in self.symbols:\n            data = self.AddData(QuantpediaFutures, symbol, Resolution.Daily)\n            data.SetLeverage(5)\n            data.SetFeeModel(CustomFeeModel())\n            self.data[symbol] = deque()\n        \n        self.recent_month = -1\n\n    def OnData(self, data):\n        rebalance_flag = False\n        \n        for symbol in self.symbols:\n            if symbol in data:\n                if self.recent_month != self.Time.month:\n                    rebalance_flag = True\n                    \n                if data[symbol]:\n                    price = data[symbol].Value\n                    self.data[symbol].append(price)\n\n        if rebalance_flag:\n            self.recent_month = self.Time.month\n        \n        rf_rate = 0\n        if self.Securities[self.risk_free_rate].GetLastData() and (self.Time.date() - self.Securities[self.risk_free_rate].GetLastData().Time.date()).days < 5:\n            rf_rate = self.Securities[self.risk_free_rate].Price\n        else:\n            return\n            \n        if self.Securities[self.cash].GetLastData() and (self.Time.date() - self.Securities[self.cash].GetLastData().Time.date()).days >= 5:\n            return\n            \n        market_prices = np.array(self.data[self.symbols[0]])\n        oil_prices = np.array(self.data[self.symbols[1]])\n        \n        # At least one year of data is ready.\n        if len(market_prices) < 13 or len(oil_prices) < 13:\n            return\n        \n        # Trim price series lengths.\n        min_size = min(len(market_prices), len(oil_prices))\n        market_prices = market_prices[-min_size:]\n        oil_prices = oil_prices[-min_size:]\n        \n        market_returns = (market_prices[1:] - market_prices[:-1]) / market_prices[:-1]\n        oil_returns = (oil_prices[1:] - oil_prices[:-1]) / oil_prices[:-1]\n        \n        # Simple Linear Regression\n        # Y = C + (M * X)\n        # Y = α + (β ∗ X)\n\n        # Y = Dependent variable (output/outcome/prediction/estimation)\n        # C/α = Constant (Y-Intercept)\n        # M/β = Slope of the regression line (the effect that X has on Y)\n        # X = Independent variable (input variable used in the prediction of Y)\n\n        slope, intercept, r_value, p_value, std_err = stats.linregress(oil_returns[:-1], market_returns[1:])\n        X = oil_returns[-1]\n        expected_market_return = intercept + (slope * X)\n        \n        if expected_market_return > rf_rate:\n            self.SetHoldings(self.symbols[0], 1)\n        else:\n            if self.Securities[self.cash].Price != 0:\n                self.SetHoldings(self.cash, 1)"
  },
  {
    "path": "static/strategies/currency-momentum-factor.py",
    "content": "# region imports\nfrom AlgorithmImports import *\n\n# endregion\n# Custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n\n\n# Quandl \"value\" data\nclass QuandlValue(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = \"Value\"\n\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\";\")\n\n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data[\"back_adjusted\"] = float(split[1])\n        data[\"spliced\"] = float(split[2])\n        data.Value = float(split[1])\n\n        return data\n\n\n# https://quantpedia.com/strategies/currency-momentum-factor/\n#\n# Create an investment universe consisting of several currencies (10-20). Go long three currencies with the highest 12-month momentum against USD\n# and go short three currencies with the lowest 12-month momentum against USD. Cash not used as margin invest on overnight rates. Rebalance monthly.\n\nimport data_tools\nfrom AlgorithmImports import *\n\n\nclass CurrencyMomentumFactor(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.data = {}\n        self.period = 12 * 21\n        self.SetWarmUp(self.period, Resolution.Daily)\n\n        self.symbols = [\n            \"CME_AD1\",  # Australian Dollar Futures, Continuous Contract #1\n            \"CME_BP1\",  # British Pound Futures, Continuous Contract #1\n            \"CME_CD1\",  # Canadian Dollar Futures, Continuous Contract #1\n            \"CME_EC1\",  # Euro FX Futures, Continuous Contract #1\n            \"CME_JY1\",  # Japanese Yen Futures, Continuous Contract #1\n            \"CME_MP1\",  # Mexican Peso Futures, Continuous Contract #1\n            \"CME_NE1\",  # New Zealand Dollar Futures, Continuous Contract #1\n            \"CME_SF1\",  # Swiss Franc Futures, Continuous Contract #1\n        ]\n\n        for symbol in self.symbols:\n            data = self.AddData(data_tools.QuantpediaFutures, symbol, Resolution.Daily)\n            data.SetFeeModel(data_tools.CustomFeeModel())\n            data.SetLeverage(5)\n            self.data[symbol] = self.ROC(symbol, self.period, Resolution.Daily)\n\n        self.recent_month = -1\n\n    def OnData(self, data):\n        if self.IsWarmingUp:\n            return\n\n        # rebalance monthly\n        if self.Time.month == self.recent_month:\n            return\n        self.recent_month = self.Time.month\n\n        perf = {\n            x[0]: x[1].Current.Value\n            for x in self.data.items()\n            if self.data[x[0]].IsReady and x[0] in data and data[x[0]]\n        }\n\n        long = []\n        short = []\n        if len(perf) >= 6:\n            sorted_by_performance = sorted(\n                perf.items(), key=lambda x: x[1], reverse=True\n            )\n            long = [x[0] for x in sorted_by_performance[:3]]\n            short = [x[0] for x in sorted_by_performance[-3:]]\n\n        # trade execution\n        invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]\n        for symbol in invested:\n            if symbol not in long + short:\n                self.Liquidate(symbol)\n\n        for symbol in long:\n            self.SetHoldings(symbol, 1 / len(long))\n        for symbol in short:\n            self.SetHoldings(symbol, -1 / len(short))\n"
  },
  {
    "path": "static/strategies/currency-value-factor-ppp-strategy.py",
    "content": "# region imports\nfrom AlgorithmImports import *\n\n# endregion\n# Custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n\n\n# Quandl \"value\" data\nclass QuandlValue(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = \"Value\"\n\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\";\")\n\n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data[\"back_adjusted\"] = float(split[1])\n        data[\"spliced\"] = float(split[2])\n        data.Value = float(split[1])\n\n        return data\n\n\n# https://quantpedia.com/strategies/currency-value-factor-ppp-strategy/\n#\n# Create an investment universe consisting of several currencies (10-20). Use the latest OECD Purchasing Power Parity figure to assess\n# the fair value of each currency versus USD in the month of publishing and then use monthly CPI changes and exchange rate changes to\n# create fair PPP value for the month prior to the current month. Go long three currencies that are the most undervalued (lowest PPP\n# fair value figure) and go short three currencies that are the most overvalued (highest PPP fair value figure). Invest cash not used\n# as margin on overnight rates. Rebalance quarterly or monthly.\n#\n# QC implementation changes:\n#   - Yearly rebalance instead of quarterly is performed.\n\nimport data_tools\nfrom AlgorithmImports import *\n\n\nclass CurrencyValueFactorPPPStrategy(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        # currency future symbol and PPP yearly quandl symbol\n        # PPP source: https://www.quandl.com/data/ODA-IMF-Cross-Country-Macroeconomic-Statistics?keyword=%20United%20States%20Implied%20PPP%20Conversion%20Rate\n        self.symbols = {\n            \"CME_AD1\": \"ODA/AUS_PPPEX\",  # Australian Dollar Futures, Continuous Contract #1\n            \"CME_BP1\": \"ODA/GBR_PPPEX\",  # British Pound Futures, Continuous Contract #1\n            \"CME_CD1\": \"ODA/CAD_PPPEX\",  # Canadian Dollar Futures, Continuous Contract #1\n            \"CME_EC1\": \"ODA/DEU_PPPEX\",  # Euro FX Futures, Continuous Contract #1\n            \"CME_JY1\": \"ODA/JPN_PPPEX\",  # Japanese Yen Futures, Continuous Contract #1\n            \"CME_NE1\": \"ODA/NZL_PPPEX\",  # New Zealand Dollar Futures, Continuous Contract #1\n            \"CME_SF1\": \"ODA/CHE_PPPEX\",  # Swiss Franc Futures, Continuous Contract #1\n        }\n\n        for symbol in self.symbols:\n            data = self.AddData(data_tools.QuantpediaFutures, symbol, Resolution.Daily)\n            data.SetFeeModel(data_tools.CustomFeeModel())\n            data.SetLeverage(5)\n\n            # PPP quandl data.\n            ppp_symbol = self.symbols[symbol]\n            self.AddData(data_tools.QuandlValue, ppp_symbol, Resolution.Daily)\n\n        self.recent_month = -1\n\n    def OnData(self, data):\n        if self.recent_month == self.Time.month:\n            return\n        self.recent_month = self.Time.month\n\n        # January rebalance\n        if self.recent_month == 1:\n            ppp = {}\n            for symbol, ppp_symbol in self.symbols.items():\n                # if symbol in data and data[symbol]:\n                if (\n                    self.Securities[symbol].GetLastData()\n                    and (\n                        self.Time.date()\n                        - self.Securities[symbol].GetLastData().Time.date()\n                    ).days\n                    < 3\n                ):\n                    # new ppp data arrived\n                    if ppp_symbol in data and data[ppp_symbol]:\n                        ppp[symbol] = data[ppp_symbol].Value\n\n            count = 3\n            long = []\n            short = []\n            if len(ppp) >= count * 2:\n                # ppp sorting\n                sorted_by_ppp = sorted(ppp.items(), key=lambda x: x[1], reverse=True)\n                long = [x[0] for x in sorted_by_ppp[-count:]]\n                short = [x[0] for x in sorted_by_ppp[:count]]\n\n            # trade execution\n            invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]\n            for symbol in invested:\n                if symbol not in long + short:\n                    self.Liquidate(symbol)\n\n            for symbol in long:\n                self.SetHoldings(symbol, 1 / len(long))\n            for symbol in short:\n                self.SetHoldings(symbol, -1 / len(short))\n"
  },
  {
    "path": "static/strategies/dispersion-trading.py",
    "content": "# https://quantpedia.com/strategies/dispersion-trading/\n#\n# The investment universe consists of stocks from the S&P 100 index.\n# Trading vehicles are options on stocks from this index and also options on the index itself.\n# The investor uses analyst forecasts of earnings per share from the Institutional Brokers Estimate System (I/B/E/S) database and\n# computes for each firm the mean absolute difference scaled by an indicator of earnings uncertainty (see page 24 in the source academic paper for detailed methodology).\n# Each month, investor sorts stocks into quintiles based on the size of belief disagreement.\n# He buys puts of stocks with the highest belief disagreement and sells the index puts with Black-Scholes deltas ranging from -0.8 to -0.2.\n#\n# QC Implementation:\n#   - Due to lack of data, strategy only buys puts of 100 liquid US stocks and sells the SPX index puts.\n\n#region imports\nfrom AlgorithmImports import *\nfrom numpy import floor\n#endregion\n\nclass DispersionTrading(QCAlgorithm):\n    \n    def Initialize(self):\n        self.SetStartDate(2010, 1, 1)\n        self.SetCash(1000000)\n        \n        self.min_expiry = 20\n        self.max_expiry = 60\n        \n        self.index_symbol = self.AddIndex('SPX').Symbol\n        self.percentage_traded = 1.0\n        \n        self.spx_contract = None\n        self.selected_symbols = []\n        self.subscribed_contracts = {}\n        \n        self.coarse_count = 100\n        self.UniverseSettings.Resolution = Resolution.Minute\n        self.AddUniverse(self.CoarseSelectionFunction)\n        self.SetSecurityInitializer(lambda x: x.SetDataNormalizationMode(DataNormalizationMode.Raw))\n        self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(5)\n\n    def CoarseSelectionFunction(self, coarse):\n        # rebalance on SPX contract expiration (should be on monthly basis)\n        if len(self.selected_symbols) != 0:\n            return Universe.Unchanged\n        \n        # select top n stocks by dollar volume\n        selected = sorted([x for x in coarse if x.HasFundamentalData and x.Market == 'usa' and x.Price > 5],\n                key=lambda x: x.DollarVolume, reverse=True)[:self.coarse_count]\n                \n        self.selected_symbols = [x.Symbol for x in selected]\n\n        return self.selected_symbols\n\n    def OnData(self, data):\n        # liquidate portfolio, when SPX contract is about to expire in 2 days\n        if self.index_symbol in self.subscribed_contracts and self.subscribed_contracts[self.index_symbol].ID.Date.date() - timedelta(2) <= self.Time.date():\n            self.subscribed_contracts.clear()   # perform new subscribtion\n            self.selected_symbols.clear()       # perform new selection\n            self.Liquidate()\n            \n        if len(self.subscribed_contracts) == 0:\n            if self.Portfolio.Invested:\n                self.Liquidate()\n            \n            # NOTE order is important, index should come first\n            for symbol in [self.index_symbol] + self.selected_symbols:\n                # subscribe to contract\n                contracts = self.OptionChainProvider.GetOptionContractList(symbol, self.Time)\n                # get current price for stock\n                underlying_price = self.Securities[symbol].Price\n                \n                # get strikes from stock contracts\n                strikes = [i.ID.StrikePrice for i in contracts]\n                \n                # check if there is at least one strike    \n                if len(strikes) <= 0:\n                    continue\n            \n                # at the money\n                atm_strike = min(strikes, key=lambda x: abs(x-underlying_price))\n\n                # filtred contracts based on option rights and strikes\n                atm_puts = [i for i in contracts if i.ID.OptionRight == OptionRight.Put and \n                                                     i.ID.StrikePrice == atm_strike and \n                                                     self.min_expiry <= (i.ID.Date - self.Time).days <= self.max_expiry]\n\n                # index contract is found\n                if symbol == self.index_symbol and len(atm_puts) == 0:\n                    # cancel whole selection since index contract was not found\n                    return\n                    \n                # make sure there are enough contracts\n                if len(atm_puts) > 0:\n                    # sort by expiry\n                    atm_put = sorted(atm_puts, key = lambda item: item.ID.Date, reverse=True)[0]\n                    \n                    # add contract\n                    option = self.AddOptionContract(atm_put, Resolution.Minute)\n                    option.PriceModel = OptionPriceModels.CrankNicolsonFD()\n                    option.SetDataNormalizationMode(DataNormalizationMode.Raw)\n\n                    # store subscribed atm put contract\n                    self.subscribed_contracts[symbol] = atm_put\n        \n        # perform trade, when spx and stocks contracts are selected            \n        if not self.Portfolio.Invested and len(self.subscribed_contracts) != 0 and self.index_symbol in self.subscribed_contracts:\n            index_option_contract = self.subscribed_contracts[self.index_symbol]\n            # make sure subscribed SPX contract has data\n            if self.Securities.ContainsKey(index_option_contract):\n                if self.Securities[index_option_contract].Price != 0 and self.Securities[index_option_contract].IsTradable:\n                    # sell SPX ATM put contract\n                    self.Securities[index_option_contract].MarginModel = BuyingPowerModel(2)\n                    price = self.Securities[self.index_symbol].Price\n                    if price != 0:\n                        q = floor((self.Portfolio.TotalPortfolioValue * self.percentage_traded) / (price*100))\n                        self.Sell(index_option_contract, q)\n\n                    # buy stock's ATM put contracts            \n                    long_count = len(self.subscribed_contracts) - 1     # minus index symbol\n                    for stock_symbol, stock_option_contract in self.subscribed_contracts.items():\n                        if stock_symbol == self.index_symbol:\n                            continue\n                        \n                        if self.Securities[stock_option_contract].Price != 0 and self.Securities[stock_option_contract].IsTradable:\n                            # buy contract\n                            self.Securities[stock_option_contract].MarginModel = BuyingPowerModel(2)\n                            if self.Securities.ContainsKey(stock_option_contract):\n                                price = self.Securities[stock_symbol].Price\n                                if price != 0:\n                                    q = floor(((self.Portfolio.TotalPortfolioValue / long_count) * self.percentage_traded) / (price*100))\n                                    self.Buy(stock_option_contract, q)\n\n# Custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/dollar-carry-trade.py",
    "content": "# https://quantpedia.com/strategies/dollar-carry-trade/\n#\n# The investment universe consists of currencies from developed countries (the Euro area, Australia, Canada, Denmark, Japan, New Zealand, Norway, Sweden,\n# Switzerland, and the United Kingdom). The average forward discount (AFD) is calculated for this basket of currencies (each currency has an equal weight).\n# The average 3-month rate could be used instead of the AFD in the calculation. The AFD is then compared to the 3-month US Treasury rate. The investor\n# goes long on the US dollar and goes short on the basket of currencies if the 3-month US Treasury rate is higher than the AFD. The investor goes short\n# on the US dollar and long on the basket of currencies if the 3-month US Treasury rate is higher than the AFD. The portfolio is rebalanced monthly.\n\nimport numpy as np\nfrom AlgorithmImports import *\n\n\nclass DollarCarryTrade(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.symbols = {\n            \"CME_AD1\": \"OECD/KEI_IR3TIB01_AUS_ST_M\",  # Australian Dollar Futures, Continuous Contract #1\n            \"CME_BP1\": \"OECD/KEI_IR3TIB01_GBR_ST_M\",  # British Pound Futures, Continuous Contract #1\n            \"CME_CD1\": \"OECD/KEI_IR3TIB01_CAN_ST_M\",  # Canadian Dollar Futures, Continuous Contract #1\n            \"CME_EC1\": \"OECD/KEI_IR3TIB01_EA19_ST_M\",  # Euro FX Futures, Continuous Contract #1\n            \"CME_JY1\": \"OECD/KEI_IR3TIB01_JPN_ST_M\",  # Japanese Yen Futures, Continuous Contract #1\n            \"CME_MP1\": \"OECD/KEI_IR3TIB01_MEX_ST_M\",  # Mexican Peso Futures, Continuous Contract #1\n            \"CME_NE1\": \"OECD/KEI_IR3TIB01_NZL_ST_M\",  # New Zealand Dollar Futures, Continuous Contract #1\n            \"CME_SF1\": \"SNB/ZIMOMA\",  # Swiss Franc Futures, Continuous Contract #1\n        }\n\n        for symbol in self.symbols:\n            data = self.AddData(QuantpediaFutures, symbol, Resolution.Daily)\n            data.SetFeeModel(CustomFeeModel())\n            data.SetLeverage(5)\n\n            # Interbank rate data.\n            cash_rate_symbol = self.symbols[symbol]\n            self.AddData(QuandlValue, cash_rate_symbol, Resolution.Daily)\n\n        self.treasury_rate = self.AddData(\n            QuandlValue, \"FRED/DGS3MO\", Resolution.Daily\n        ).Symbol\n\n    def OnData(self, data):\n        fd = {}\n        for future_symbol, cash_rate_symbol in self.symbols.items():\n            if cash_rate_symbol in data and data[cash_rate_symbol]:\n                if (\n                    self.Securities[future_symbol].GetLastData()\n                    and (\n                        self.Time.date()\n                        - self.Securities[future_symbol].GetLastData().Time.date()\n                    ).days\n                    < 5\n                ):\n                    cash_rate = data[cash_rate_symbol].Value\n                    # Update cash rate only once a month.\n                    fd[future_symbol] = cash_rate\n\n        if len(fd) == 0:\n            return\n\n        afd = np.mean([x[1] for x in fd.items()])\n\n        if (\n            self.Securities[self.treasury_rate].GetLastData()\n            and (\n                self.Time.date()\n                - self.Securities[self.treasury_rate].GetLastData().Time.date()\n            ).days\n            < 5\n        ):\n            treasuries_3m_rate = self.Securities[self.treasury_rate].Price\n\n            count = len(self.symbols)\n            if treasuries_3m_rate > afd:\n                # Long on the US dollar and goes short on the basket of currencies.\n                for symbol in self.symbols:\n                    self.SetHoldings(symbol, -1 / count)\n            else:\n                # Short on the US dollar and long on the basket of currencies.\n                for symbol in self.symbols:\n                    self.SetHoldings(symbol, 1 / count)\n\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\";\")\n\n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data[\"back_adjusted\"] = float(split[1])\n        data[\"spliced\"] = float(split[2])\n        data.Value = float(split[1])\n\n        return data\n\n\n# Quandl \"value\" data\nclass QuandlValue(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = \"Value\"\n\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n"
  },
  {
    "path": "static/strategies/earnings-announcement-premium.py",
    "content": "# https://quantpedia.com/strategies/earnings-announcement-premium/\n#\n# The investment universe consists of all stocks from the CRSP database. At the beginning of every calendar month, stocks are ranked in ascending \n# order on the basis of the volume concentration ratio, which is defined as the volume of the previous 16 announcement months divided by the total\n# volume in the previous 48 months. The ranked stocks are assigned to one of 5 quintile portfolios. Within each quintile, stocks are assigned to\n# one of two portfolios (expected announcers and expected non-announcers) using the predicted announcement based on the previous year. All stocks\n# are value-weighted within a given portfolio, and portfolios are rebalanced every calendar month to maintain value weights. The investor invests\n# in a long-short portfolio, which is a zero-cost portfolio that holds the portfolio of high volume expected announcers and sells short the \n# portfolio of high volume expected non-announcers.\n#\n# QC implementation changes:\n#   - Universe consists of 1000 most liquid stocks traded on NYSE, AMEX, or NASDAQ.\n\nfrom collections import deque\nfrom AlgorithmImports import *\n\nclass EarningsAnnouncementPremium(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000) \n\n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        \n        self.period = 21\n        self.month_period = 48\n\n        # Volume daily data.\n        self.data = {}\n\n        # Volume monthly data.\n        self.monthly_volume = {}\n\n        self.coarse_count = 1000\n        self.weight = {}\n        \n        self.selection_flag = True\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(self.DateRules.MonthStart(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Selection)\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(10)\n            \n    def CoarseSelectionFunction(self, coarse):\n        # Update the rolling window every day.\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            # Store monthly price.\n            if symbol in self.data:\n                self.data[symbol].Add(stock.Volume)\n            \n        if not self.selection_flag:\n            return Universe.Unchanged\n        \n        # selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa']\n        selected = [x.Symbol\n            for x in sorted([x for x in coarse if x.HasFundamentalData and x.Market == 'usa'],\n                key = lambda x: x.DollarVolume, reverse = True)[:self.coarse_count]]\n                \n        # Warmup volume rolling windows.\n        for symbol in selected:\n            # Warmup data.\n            if symbol not in self.data:\n                self.data[symbol] = RollingWindow[float](self.period)\n                \n                history = self.History(symbol, self.period, Resolution.Daily)\n                if history.empty:\n                    self.Debug(f\"No history for {symbol} yet\")\n                    continue\n                volumes = history.loc[symbol].volume\n                for _, volume in volumes.iteritems():\n                    self.data[symbol].Add(volume)\n                \n        return [x for x in selected if self.data[x].IsReady]\n\n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0 and \\\n                    ((x.SecurityReference.ExchangeId == \"NYS\") or (x.SecurityReference.ExchangeId == \"NAS\") or (x.SecurityReference.ExchangeId == \"ASE\"))]\n                    \n        # if len(fine) > self.coarse_count:\n        #     sorted_by_market_cap = sorted(fine, key = lambda x: x.MarketCap, reverse=True)\n        #     top_by_market_cap = sorted_by_market_cap[:self.coarse_count]\n        # else:\n        #     top_by_market_cap = fine\n        \n        top_by_market_cap = fine\n            \n        fine_symbols = [x.Symbol for x in top_by_market_cap]\n            \n        # Ratio/market cap pair.\n        volume_concentration_ratio = {}\n        for stock in top_by_market_cap:\n            symbol = stock.Symbol\n            \n            if symbol not in self.monthly_volume:\n                self.monthly_volume[symbol] = deque(maxlen = self.month_period)\n\n            monthly_vol = sum([x for x in self.data[symbol]])\n            last_month_date = self.Time - timedelta(days = self.Time.day)\n            last_file_date = stock.EarningReports.FileDate # stock annoucement day\n            was_announcement_month = (last_file_date.year == last_month_date.year and last_file_date.month == last_month_date.month)    # Last month was announcement date.\n            self.monthly_volume[symbol].append(VolumeData(last_month_date, monthly_vol, was_announcement_month))\n            \n            # 48 months of volume data is ready.\n            if len(self.monthly_volume[symbol]) == self.monthly_volume[symbol].maxlen:\n                # Volume concentration ratio calc.\n                announcement_count = 16\n                announcement_volumes = [x.Volume for x in self.monthly_volume[symbol] if x.WasAnnouncementMonth][-announcement_count:]\n\n                if len(announcement_volumes) == announcement_count:\n                    announcement_months_volume = sum(announcement_volumes)\n                    total_volume = sum([x.Volume for x in self.monthly_volume[symbol]])\n                    \n                    if announcement_months_volume != 0 and total_volume != 0:\n                        # Store ratio, market cap pair.\n                        volume_concentration_ratio[stock] = announcement_months_volume / total_volume\n        \n        # Volume sorting.\n        sorted_by_volume = sorted(volume_concentration_ratio.items(), key = lambda x: x[1], reverse = True)\n        quintile = int(len(sorted_by_volume) / 5)\n        high_volume = [x[0] for x in sorted_by_volume[:quintile]]\n            \n        # Filering announcers and non-announcers.\n        month_to_lookup = self.Time.month\n        year_to_lookup = self.Time.year - 1\n            \n        long = []\n        short = []\n        for stock in high_volume:\n            symbol = stock.Symbol\n            \n            announcement_dates = [[x.Date.year, x.Date.month] for x in self.monthly_volume[symbol] if x.WasAnnouncementMonth]\n            if [year_to_lookup, month_to_lookup] in announcement_dates:\n                long.append(stock)\n            else:\n                short.append(stock)\n\n        # Delete not updated symbols.\n        symbols_to_remove = []\n        for symbol in self.monthly_volume:\n            if symbol not in fine_symbols:\n                symbols_to_remove.append(symbol)\n        for symbol in symbols_to_remove:\n            del self.monthly_volume[symbol]\n            \n        # Market cap weighting.\n        total_market_cap_long = sum([x.MarketCap for x in long])\n        for stock in long:\n            self.weight[symbol] = stock.MarketCap  / total_market_cap_long\n        \n        total_market_cap_short = sum([x.MarketCap for x in short])\n        for stock in short:\n            self.weight[symbol] = -stock.MarketCap  / total_market_cap_short\n\n        return [x[0] for x in self.weight.items()]\n    \n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n        \n        # Trade execution.\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.weight:\n                self.Liquidate(symbol)\n\n        for symbol, w in self.weight.items():\n            if self.Securities[symbol].Price != 0:  # Prevent error message.\n                self.SetHoldings(symbol, w)\n        \n        self.weight.clear()\n        \n    def Selection(self):\n        self.selection_flag = True\n\n# Monthly volume data.\nclass VolumeData():\n    def __init__(self, date, monthly_volume, was_announcement_month):\n        self.Date = date\n        self.Volume = monthly_volume\n        self.WasAnnouncementMonth = was_announcement_month\n    \n# Custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/earnings-announcements-combined-with-stock-repurchases.py",
    "content": "# https://quantpedia.com/strategies/earnings-announcements-combined-with-stock-repurchases/\n#\n# The investment universe consists of stocks from NYSE/AMEX/Nasdaq (no ADRs, CEFs or REITs), bottom 25% of firms by market cap are dropped.\n# Each quarter, the investor looks for companies that announce a stock repurchase program (with announced buyback for at least 5% of outstanding stocks) \n# during days -30 to -15 before the earnings announcement date for each company.\n# Investor goes long stocks with announced buybacks during days -10 to +15 around an earnings announcement.\n# The portfolio is equally weighted and rebalanced daily.\n#\n# QC Implementation:\n#   - Universe consists of tickers, which have earnings annoucement.\n\n#region imports\nfrom AlgorithmImports import *\nimport numpy as np\n#endregion\n\nclass EarningsAnnouncementsCombinedWithStockRepurchases(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2011, 1, 1) # Buyback data strats at 2011\n        self.SetCash(100000) \n        \n        self.fine = {}\n        self.price = {}\n        self.managed_symbols = []\n        self.earnings_universe = []\n        \n        self.earnings = {}\n        self.buybacks = {}\n        \n        self.max_traded_stocks = 40 # maximum number of trading stocks\n        self.quantile = 4\n        \n        self.symbol = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n        \n        # load earnings dates\n        csv_data = self.Download('data.quantpedia.com/backtesting_data/economic/earning_dates.csv')\n        lines = csv_data.split('\\r\\n')\n        \n        for line in lines:\n            line_split = line.split(';')\n            date = line_split[0]\n            \n            if date == '' :\n                continue\n            \n            date = datetime.strptime(date, \"%Y-%m-%d\").date()\n            self.earnings[date] = []\n            \n            for ticker in line_split[1:]: # skip date in current line\n                self.earnings[date].append(ticker)\n                \n                if ticker not in self.earnings_universe:\n                    self.earnings_universe.append(ticker)\n        \n        # load buyback dates\n        csv_data = self.Download('data.quantpedia.com/backtesting_data/equity/BUY_BACKS.csv')\n        lines = csv_data.split('\\r\\n')\n        \n        for line in lines[1:]: # skip header\n            line_split = line.split(';')\n            date = line_split[0]\n            \n            if date == '' :\n                continue\n            \n            date = datetime.strptime(date, \"%d.%m.%Y\").date()\n            self.buybacks[date] = []\n            \n            for ticker in line_split[1:]: # skip date in current line\n                self.buybacks[date].append(ticker)\n        \n        self.months_counter = 0\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(self.DateRules.MonthStart(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Selection)\n        \n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(5)\n            \n    def CoarseSelectionFunction(self, coarse):\n        # update stocks last prices\n        for stock in coarse:\n            ticker = stock.Symbol.Value\n            \n            if ticker in self.earnings_universe:\n                # store stock's last price\n                self.price[ticker] = stock.AdjustedPrice\n        \n        # rebalance quarterly\n        if not self.selection_flag:\n            return Universe.Unchanged\n        self.selection_flag = False\n        \n        # select stocks, which had spin off\n        selected = [x.Symbol for x in coarse if x.Symbol.Value in self.earnings_universe]\n\n        return selected\n        \n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0 and \n                                    ((x.SecurityReference.ExchangeId == \"NYS\") or\n                                    (x.SecurityReference.ExchangeId == \"NAS\") or \n                                    (x.SecurityReference.ExchangeId == \"ASE\"))]\n        \n        if len(fine) < self.quantile:\n            return Universe.Unchanged\n        \n        # exclude 25% stocks with lowest market capitalization\n        quantile = int(len(fine) / self.quantile)\n        sorted_by_market_cap = sorted(fine, key = lambda x: x.MarketCap)\n        selected = sorted_by_market_cap[quantile:]\n        self.fine = {x.Symbol.Value : x.Symbol for x in selected}\n        \n        return list(self.fine.values())\n\n    def OnData(self, data:Slice) -> None:\n        remove_managed_symbols = []\n        # maybe there should be BDay(15)\n        liquidate_date = self.Time.date() - timedelta(15)\n        \n        # check if bought stocks have 15 days after earnings annoucemnet\n        for managed_symbol in self.managed_symbols:\n            if managed_symbol.earnings_date >= liquidate_date:\n                remove_managed_symbols.append(managed_symbol)\n                \n                # liquidate stock by selling it's quantity\n                self.MarketOrder(managed_symbol.symbol, -managed_symbol.quantity)\n                \n        # remove liquidated stocks from self.managed_symbols\n        for managed_symbol in remove_managed_symbols:\n            self.managed_symbols.remove(managed_symbol)\n        \n        # maybe there should be BDay(10)\n        after_current = self.Time.date() + timedelta(10)\n        \n        if after_current in self.earnings:\n            # this stocks has earnings annoucement after 10 days\n            stocks_with_earnings = self.earnings[after_current]\n            \n            # 30 days before earnings annoucement\n            buyback_start = self.Time.date() - timedelta(20)\n            # 15 days before earnings annoucement\n            buyback_end = self.Time.date() - timedelta(5)\n            \n            stocks_with_buyback = [] # storing stocks with buyback in period -30 to -15 days before earnings annoucement\n            \n            for buyback_date, tickers in self.buybacks.items():\n                # check if buyback date is in period before earnings annoucement\n                if buyback_date >= buyback_start and buyback_date <= buyback_end:\n                    # iterate through each stock ticker for buyback date\n                    for ticker in tickers:\n                        # add stock ticker if it isn't already added, it has earnings annoucement after 10 days and was selected in fine\n                        if (ticker not in stocks_with_buyback) and (ticker in stocks_with_earnings) and (ticker in self.fine):\n                            stocks_with_buyback.append(self.fine[ticker])\n                            \n            # buying stocks buyback in period -30 to -15 days before earnings annoucement\n            # and stocks, which have earnings date -10 days before current date\n            for symbol in stocks_with_buyback:\n                # check if there is a place in Portfolio for trading current stock\n                if not len(self.managed_symbols) < self.max_traded_stocks:\n                    continue\n                \n                # calculate stock quantity\n                weight = self.Portfolio.TotalPortfolioValue / self.max_traded_stocks\n                quantity = np.floor(weight / self.price[symbol.Value])\n                \n                # go long stock\n                self.MarketOrder(symbol, quantity)\n                \n                # store stock's ticker, earnings date and traded quantity\n                if symbol in data and data[symbol]:\n                    self.managed_symbols.append(ManagedSymbol(symbol, after_current, quantity))\n        \n    def Selection(self):\n        # quarterly selection\n        if self.months_counter % 3 == 0:\n            self.selection_flag = True\n        self.months_counter += 1\n        \nclass ManagedSymbol():\n    def __init__(self, symbol, earnings_date, quantity):\n        self.symbol = symbol\n        self.earnings_date = earnings_date\n        self.quantity = quantity\n        \n# custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/earnings-quality-factor.py",
    "content": "# https://quantpedia.com/strategies/earnings-quality-factor/\n#\n# The investment universe consists of all non-financial stocks from NYSE, Amex and Nasdaq. Big stocks are defined as the largest stocks\n# that make up 90% of the total market cap within the region, while small stocks make up the remaining 10% of the market cap. Investor defines\n# breakpoints by the 30th and 70th percentiles of the multiple “Earnings Quality” ratios between large caps and small caps.\n# The first “Earnings Quality” ratio is defined by cash flow relative to reported earnings. The high-quality earnings firms are characterized\n# by high cash flows (relative to reported earnings) while the low-quality firms are characterized by high reported earnings (relative to cash flow).\n# The second factor is based on return on equity (ROE) to exploit the well-documented “profitability anomaly” by going long high-ROE firms\n# (top 30%) and short low-ROE firms (bottom 30%). The third ratio – CF/A (cash flow to assets) factor goes long firms with high cash flow to total assets.\n# The fourth ratio – D/A (debt to assets) factor goes long firms with low leverage and short firms with high leverage.\n# The investor builds a scored composite quality metric by computing the percentile score of each stock on each of the four quality metrics\n# (where “good” quality has a high score, so ideally a stock has low accruals, low leverage, high ROE, and high cash flow) and then add up\n# the percentiles to get a score for each stock from 0 to 400. He then forms the composite factor by going long the top 30% of small-cap\n# stocks and also large-cap stocks and short the bottom 30% of the small-cap stocks and also large-cap stocks and cap-weighting individual\n# stocks within the portfolios. The final factor portfolio is formed at the end of each June and is rebalanced yearly.\n#\n# QC implementation changes:\n#   - Universe consists of top 3000 US non-financial stocks by market cap from NYSE, AMEX and NASDAQ.\n\n\nclass EarningsQualityFactor(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.coarse_count = 3000\n\n        self.symbol = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n\n        self.accruals_data = {}\n\n        self.long = []\n        self.short = []\n\n        self.data = {}\n\n        self.selection_flag = True\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n\n        self.Schedule.On(\n            self.DateRules.MonthEnd(self.symbol),\n            self.TimeRules.AfterMarketOpen(self.symbol),\n            self.Selection,\n        )\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetLeverage(10)\n            security.SetFeeModel(CustomFeeModel(self))\n\n    def CoarseSelectionFunction(self, coarse):\n        if not self.selection_flag:\n            return Universe.Unchanged\n\n        selected = [\n            x.Symbol for x in coarse if x.HasFundamentalData and x.Market == \"usa\"\n        ]\n\n        return selected\n\n    def FineSelectionFunction(self, fine):\n        fine = [\n            x\n            for x in fine\n            if x.MarketCap != 0\n            and x.CompanyReference.IndustryTemplateCode != \"B\"\n            and (\n                (x.SecurityReference.ExchangeId == \"NYS\")\n                or (x.SecurityReference.ExchangeId == \"NAS\")\n                or (x.SecurityReference.ExchangeId == \"ASE\")\n            )\n            and x.FinancialStatements.BalanceSheet.CurrentAssets.Value != 0\n            and x.FinancialStatements.BalanceSheet.CashAndCashEquivalents.Value != 0\n            and x.FinancialStatements.BalanceSheet.CurrentLiabilities.Value != 0\n            and x.FinancialStatements.BalanceSheet.CurrentDebt.Value != 0\n            and x.FinancialStatements.IncomeStatement.DepreciationAndAmortization.Value\n            != 0\n            and x.FinancialStatements.BalanceSheet.GrossPPE.Value != 0\n            and x.FinancialStatements.IncomeStatement.TotalRevenueAsReported.Value != 0\n            and x.FinancialStatements.CashFlowStatement.OperatingCashFlow.Value != 0\n            and x.EarningReports.BasicEPS.Value != 0\n            and x.EarningReports.BasicAverageShares.Value != 0\n            and x.OperationRatios.DebttoAssets.Value != 0\n            and x.OperationRatios.ROE.Value != 0\n        ]\n\n        if len(fine) > self.coarse_count:\n            sorted_by_market_cap = sorted(fine, key=lambda x: x.MarketCap, reverse=True)\n            top_by_market_cap = [x for x in sorted_by_market_cap[: self.coarse_count]]\n        else:\n            top_by_market_cap = fine\n\n        for stock in top_by_market_cap:\n            symbol = stock.Symbol\n\n            if symbol not in self.accruals_data:\n                # Data for previous year.\n                self.accruals_data[symbol] = None\n\n            # Accrual calc.\n            current_accruals_data = AcrrualsData(\n                stock.FinancialStatements.BalanceSheet.CurrentAssets.Value,\n                stock.FinancialStatements.BalanceSheet.CashAndCashEquivalents.Value,\n                stock.FinancialStatements.BalanceSheet.CurrentLiabilities.Value,\n                stock.FinancialStatements.BalanceSheet.CurrentDebt.Value,\n                stock.FinancialStatements.BalanceSheet.IncomeTaxPayable.Value,\n                stock.FinancialStatements.IncomeStatement.DepreciationAndAmortization.Value,\n                stock.FinancialStatements.BalanceSheet.TotalAssets.Value,\n                stock.FinancialStatements.IncomeStatement.TotalRevenueAsReported.Value,\n            )\n\n            # There is not previous accruals data.\n            if not self.accruals_data[symbol]:\n                self.accruals_data[symbol] = current_accruals_data\n                continue\n\n            current_accruals = self.CalculateAccruals(\n                current_accruals_data, self.accruals_data[symbol]\n            )\n\n            # cash flow to assets\n            CFA = (\n                stock.FinancialStatements.CashFlowStatement.OperatingCashFlow.Value\n                / (\n                    stock.EarningReports.BasicEPS.Value\n                    * stock.EarningReports.BasicAverageShares.Value\n                )\n            )\n            # debt to assets\n            DA = stock.OperationRatios.DebttoAssets.Value\n            # return on equity\n            ROE = stock.OperationRatios.ROE.Value\n\n            if symbol not in self.data:\n                self.data[symbol] = None\n\n            self.data[symbol] = StockData(current_accruals, CFA, DA, ROE)\n            self.accruals_data[symbol] = current_accruals_data\n\n        # Remove not updated symbols.\n        updated_symbols = [x.Symbol for x in top_by_market_cap]\n        not_updated = [x for x in self.data if x not in updated_symbols]\n        for symbol in not_updated:\n            del self.data[symbol]\n            del self.accruals_data[symbol]\n\n        return [x[0] for x in self.data.items()]\n\n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n\n        # Sort stocks by four factors respectively.\n        sorted_by_accruals = sorted(\n            self.data.items(), key=lambda x: x[1].Accruals, reverse=True\n        )  # high score with low accrual\n        sorted_by_CFA = sorted(\n            self.data.items(), key=lambda x: x[1].CFA\n        )  # high score with high CFA\n        sorted_by_DA = sorted(\n            self.data.items(), key=lambda x: x[1].DA, reverse=True\n        )  # high score with low leverage\n        sorted_by_ROE = sorted(\n            self.data.items(), key=lambda x: x[1].ROE\n        )  # high score with high ROE\n\n        score = {}\n\n        # Assign a score to each stock according to their rank with different factors.\n        for i, obj in enumerate(sorted_by_accruals):\n            score_accruals = i\n            score_CFA = sorted_by_CFA.index(obj)\n            score_DA = sorted_by_DA.index(obj)\n            score_ROE = sorted_by_ROE.index(obj)\n            score[obj[0]] = score_accruals + score_CFA + score_DA + score_ROE\n\n        sorted_by_score = sorted(score.items(), key=lambda x: x[1], reverse=True)\n        tercile = int(len(sorted_by_score) / 3)\n        long = [x[0] for x in sorted_by_score[:tercile]]\n        short = [x[0] for x in sorted_by_score[-tercile:]]\n\n        # Trade execution.\n        # NOTE: Skip year 2007 due to data error.\n        if self.Time.year == 2007:\n            self.Liquidate()\n            return\n\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in long + short:\n                self.Liquidate(symbol)\n\n        for symbol in long:\n            if (\n                self.Securities[symbol].Price != 0\n                and self.Securities[symbol].IsTradable\n            ):  # Prevent error message.\n                self.SetHoldings(symbol, 1 / len(long))\n        for symbol in short:\n            if (\n                self.Securities[symbol].Price != 0\n                and self.Securities[symbol].IsTradable\n            ):  # Prevent error message.\n                self.SetHoldings(symbol, -1 / len(short))\n\n    # Source: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3188172\n    def CalculateAccruals(self, current_accrual_data, prev_accrual_data):\n        delta_assets = (\n            current_accrual_data.CurrentAssets - prev_accrual_data.CurrentAssets\n        )\n        delta_cash = (\n            current_accrual_data.CashAndCashEquivalents\n            - prev_accrual_data.CashAndCashEquivalents\n        )\n        delta_liabilities = (\n            current_accrual_data.CurrentLiabilities\n            - prev_accrual_data.CurrentLiabilities\n        )\n        delta_debt = current_accrual_data.CurrentDebt - prev_accrual_data.CurrentDebt\n        dep = current_accrual_data.DepreciationAndAmortization\n        total_assets_prev_year = prev_accrual_data.TotalAssets\n\n        acc = (\n            delta_assets - delta_liabilities - delta_cash + delta_debt - dep\n        ) / total_assets_prev_year\n        return acc\n\n    def Selection(self):\n        if self.Time.month == 7:\n            self.selection_flag = True\n\n\nclass AcrrualsData:\n    def __init__(\n        self,\n        current_assets,\n        cash_and_cash_equivalents,\n        current_liabilities,\n        current_debt,\n        income_tax_payable,\n        depreciation_and_amortization,\n        total_assets,\n        sales,\n    ):\n        self.CurrentAssets = current_assets\n        self.CashAndCashEquivalents = cash_and_cash_equivalents\n        self.CurrentLiabilities = current_liabilities\n        self.CurrentDebt = current_debt\n        self.IncomeTaxPayable = income_tax_payable\n        self.DepreciationAndAmortization = depreciation_and_amortization\n        self.TotalAssets = total_assets\n\n        self.Sales = sales\n\n\nclass StockData:\n    def __init__(self, accruals, cfa, da, roe):\n        self.Accruals = accruals\n        self.CFA = cfa\n        self.DA = da\n        self.ROE = roe\n\n\ndef MultipleLinearRegression(x, y):\n    x = np.array(x).T\n    x = sm.add_constant(x)\n    result = sm.OLS(endog=y, exog=x).fit()\n    return result\n\n\n# Custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n"
  },
  {
    "path": "static/strategies/esg-factor-momentum-strategy.py",
    "content": "#region imports\nfrom AlgorithmImports import *\n#endregion\n# https://quantpedia.com/strategies/esg-factor-momentum-strategy/\n#\n# The investment universe consists of stocks in the MSCI World Index. Paper uses MSCI ESG Ratings as the ESG database.\n# The ESG Momentum strategy is built by overweighting, relative to the MSCI World Index, companies that increased their\n# ESG ratings most during the recent past and underweight those with decreased ESG ratings, where the increases and decreases\n# are based on a 12-month ESG momentum. The paper uses the Barra Global Equity Model (GEM3) for portfolio construction with \n# constraints that can be found in Appendix 2. Therefore, this strategy is very specific, but we aim to present the idea, not \n# the portfolio construction. The strategy is rebalanced monthly.\n#\n# QC implementation:\n#   - Universe consists of ~700 stocks with ESG score data.\n\nfrom numpy import floor\n\nclass ESGFactorMomentumStrategy(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2009, 6, 1)\n        self.SetEndDate(2019, 12, 31)\n        self.SetCash(100000)\n        \n        # Decile weighting.\n        # True - Value weighted\n        # False - Equally weighted\n        self.value_weighting = True\n        \n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        \n        self.esg_data = self.AddData(ESGData, 'ESG', Resolution.Daily)\n        self.tickers = []\n        \n        self.holding_period = 3\n        self.managed_queue = []\n\n        # Monthly ESG decile data.\n        self.esg = {}\n        self.period = 14\n        \n        self.latest_price = {}\n        \n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n    \n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel(self))\n            security.SetLeverage(10)\n    \n    def CoarseSelectionFunction(self, coarse):\n        if not self.selection_flag:\n            return Universe.Unchanged\n        \n        self.latest_price.clear()\n        \n        selected = [x for x in coarse if (x.Symbol.Value).lower() in self.tickers]\n        \n        for stock in selected:\n            symbol = stock.Symbol\n            self.latest_price[symbol] = stock.AdjustedPrice\n\n        return [x.Symbol for x in selected]\n    \n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0]\n\n        momentum = {}\n        \n        # Momentum calc.\n        for stock in fine:\n            symbol = stock.Symbol\n            ticker = symbol.Value\n            # ESG data for 14 months is ready.\n            if ticker in self.esg and self.esg[ticker].IsReady:\n                esg_data = [x for x in self.esg[ticker]]\n                \n                esg_decile_2_months_ago = esg_data[1]\n                esg_decile_14_months_ago = esg_data[13]\n                \n                if esg_decile_14_months_ago != 0 and esg_decile_2_months_ago != 0:\n                    # Momentum as difference.\n                    # momentum_ = esg_decile_2_months_ago - esg_decile_14_months_ago\n                    \n                    # Momentum as ratio.\n                    momentum_ = (esg_decile_2_months_ago / esg_decile_14_months_ago) - 1\n                    \n                    # Store momentum/market cap pair.\n                    momentum[stock] = momentum_\n                \n        # Momentum sorting.\n        sorted_by_momentum = sorted(momentum.items(), key = lambda x: x[1], reverse = True)\n        decile = int(len(sorted_by_momentum) / 10)\n        long = [x[0] for x in sorted_by_momentum[:decile]]\n        short = [x[0] for x in sorted_by_momentum[-decile:]]\n        \n        long_symbol_q = []\n        short_symbol_q = []\n        \n        # ew\n        if not self.value_weighting:\n            if len(long) != 0:\n                long_w = self.Portfolio.TotalPortfolioValue / self.holding_period / len(long)\n                long_symbol_q = [(x.Symbol, floor(long_w / self.latest_price[x.Symbol])) for x in long]\n            \n            if len(short) != 0:\n                short_w = self.Portfolio.TotalPortfolioValue / self.holding_period / len(short)\n                short_symbol_q = [(x.Symbol, -floor(short_w / self.latest_price[x.Symbol])) for x in short]\n        # vw\n        else:\n            if len(long) != 0:\n                total_market_cap_long = sum([x.MarketCap for x in long])\n                long_w = self.Portfolio.TotalPortfolioValue / self.holding_period\n                long_symbol_q = [(x.Symbol, floor((long_w * (x.MarketCap / total_market_cap_long))) / self.latest_price[x.Symbol]) for x in long]\n            \n            short_symbol_q = []\n            if len(short) != 0:\n                total_market_cap_short = sum([x.MarketCap for x in short])\n                short_w = self.Portfolio.TotalPortfolioValue / self.holding_period\n                short_symbol_q = [(x.Symbol, -floor((short_w * (x.MarketCap / total_market_cap_short))) / self.latest_price[x.Symbol]) for x in short]\n        \n        self.managed_queue.append(RebalanceQueueItem(long_symbol_q + short_symbol_q))\n        \n        return [x.Symbol for x in long + short]\n    \n    def OnData(self, data):\n        new_data_arrived = False\n        \n        if 'ESG' in data and data['ESG']:\n            # Store universe tickers.\n            if len(self.tickers) == 0:\n                # TODO '_typename' in storage dictionary?\n                self.tickers = [x.Key for x in self.esg_data.GetLastData().GetStorageDictionary()][:-1]\n        \n            # Store history for every ticker.\n            for ticker in self.tickers:\n                ticker_u = ticker.upper()\n                if ticker_u not in self.esg:\n                    self.esg[ticker_u] = RollingWindow[float](self.period)\n                \n                decile = self.esg_data.GetLastData()[ticker]\n                self.esg[ticker_u].Add(decile)\n                \n                # trigger selection after new esg data arrived.\n                if not self.selection_flag:\n                    new_data_arrived = True\n        \n        if new_data_arrived:\n            self.selection_flag = True\n            return\n        \n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n\n        # Trade execution\n        remove_item = None\n        \n        # Rebalance portfolio\n        for item in self.managed_queue:\n            if item.holding_period == self.holding_period:\n                for symbol, quantity in item.symbol_q:\n                    if quantity >= 1:\n                        self.MarketOrder(symbol, -quantity)\n                            \n                remove_item = item\n                \n            elif item.holding_period == 0:\n                open_symbol_q = []\n                \n                for symbol, quantity in item.symbol_q:\n                    if quantity >= 1:\n                        if self.Securities[symbol].Price != 0 and self.Securities[symbol].IsTradable:\n                            self.MarketOrder(symbol, quantity)\n                            open_symbol_q.append((symbol, quantity))\n                            \n                # Only opened orders will be closed        \n                item.symbol_q = open_symbol_q\n                \n            item.holding_period += 1\n            \n        if remove_item:\n            self.managed_queue.remove(remove_item)\n\nclass RebalanceQueueItem():\n    def __init__(self, symbol_q):\n        # symbol/quantity collections\n        self.symbol_q = symbol_q  \n        self.holding_period = 0\n\n# ESG data.\nclass ESGData(PythonData):\n    def __init__(self):\n        self.tickers = []\n    \n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/economic/esg_deciles_data.csv\", SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n    \n    def Reader(self, config, line, date, isLiveMode):\n        data = ESGData()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit():\n            self.tickers = [x for x in line.split(';')][1:]\n            return None\n            \n        split = line.split(';')\n        \n        data.Time = datetime.strptime(split[0], \"%Y-%m-%d\") + timedelta(days=1)\n\n        index = 1\n        for ticker in self.tickers:\n            data[ticker] = float(split[index])\n            index += 1\n            \n        data.Value = float(split[1])\n        return data\n        \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/fed-model.py",
    "content": "# https://quantpedia.com/strategies/fed-model/\n#\n# Each month, the investor conducts a one-month predictive regression (using all available data up to that date) predicting excess stock market\n# returns using the yield gap as an independent variable. The “Yield gap” is calculated as YG = EY − y, with earnings yield EY ≡ ln (1 ++ E/P)\n# and y = ln (1 ++ Y) is the log 10 year Treasury bond yield. Then, the strategy allocates 100% in the risky asset if the forecasted excess\n# returns are positive, and otherwise, it invests 100% in the risk-free rate.\n\nfrom collections import deque\nfrom AlgorithmImports import *\nimport numpy as np\nfrom scipy import stats\n\n\nclass FEDModel(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        # monthly price data and yield gap data\n        self.data = {}\n\n        self.period = 12 * 21\n        self.SetWarmUp(self.period)\n\n        self.market = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n        self.market_data = deque()\n\n        self.cash = self.AddEquity(\"SHY\", Resolution.Daily).Symbol\n\n        # risk free rate\n        self.risk_free_rate = self.AddData(\n            QuandlValue, \"FRED/DGS3MO\", Resolution.Daily\n        ).Symbol\n\n        # 10Y bond yield symbol\n        self.bond_yield = self.AddData(\n            QuantpediaBondYield, \"US10YT\", Resolution.Daily\n        ).Symbol\n\n        # SP500 earnings yield data\n        self.sp_earnings_yield = self.AddData(\n            QuandlValue, \"MULTPL/SP500_EARNINGS_YIELD_MONTH\", Resolution.Daily\n        ).Symbol\n\n        self.yield_gap = deque()\n\n        self.recent_month = -1\n\n    def OnData(self, data):\n        rebalance_flag = False\n\n        if self.sp_earnings_yield in data and data[self.sp_earnings_yield]:\n            if self.Time.month != self.recent_month:\n                self.recent_month = self.Time.month\n                rebalance_flag = True\n\n        if not rebalance_flag:\n            # earnings yield data is no longer coming in\n            if self.Securities[self.sp_earnings_yield].GetLastData():\n                if (\n                    self.Time.date()\n                    - self.Securities[self.sp_earnings_yield].GetLastData().Time.date()\n                ).days > 31:\n                    self.Liquidate()\n            return\n\n        # pdate market price data\n        if (\n            self.market in data\n            and self.risk_free_rate in data\n            and self.bond_yield in data\n        ):\n            if (\n                data[self.market]\n                and data[self.risk_free_rate]\n                and data[self.bond_yield]\n            ):\n                market_price = data[self.market].Value\n                rf_rate = data[self.risk_free_rate].Value\n                bond_yield = data[self.bond_yield].Value\n                sp_ey = data[self.sp_earnings_yield].Value\n                if (\n                    market_price != 0\n                    and rf_rate != 0\n                    and bond_yield != 0\n                    and sp_ey != 0\n                ):\n                    self.market_data.append((market_price, rf_rate))\n\n                    yield_gap = np.log(sp_ey) - np.log(bond_yield)\n                    self.yield_gap.append(yield_gap)\n                    rebalance_flag = True\n\n        # ensure minimum data points to calculate regression\n        min_count = 6\n        if len(self.market_data) >= min_count:\n            market_closes = np.array([x[0] for x in self.market_data])\n            market_returns = (market_closes[1:] - market_closes[:-1]) / market_closes[\n                :-1\n            ]\n            rf_rates = np.array([x[1] for x in self.market_data][1:])\n            excess_returns = market_returns - rf_rates\n\n            yield_gaps = [x for x in self.yield_gap]\n\n            # linear regression\n            # Y = α + (β ∗ X)\n            # intercept = alpha\n            # slope = beta\n            beta, alpha, r_value, p_value, std_err = stats.linregress(\n                yield_gaps[1:-1], market_returns[1:]\n            )\n            X = yield_gaps[-1]\n\n            # predicted market return\n            Y = alpha + (beta * X)\n\n            # trade execution / rebalance\n            if Y > 0:\n                if self.Portfolio[self.cash].Invested:\n                    self.Liquidate(self.cash)\n                self.SetHoldings(self.market, 1)\n            else:\n                if self.Portfolio[self.market].Invested:\n                    self.Liquidate(self.market)\n                self.SetHoldings(self.cash, 1)\n\n\n# Quantpedia bond yield data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaBondYield(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/bond_yield/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaBondYield()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\",\")\n\n        data.Time = datetime.strptime(split[0], \"%Y-%m-%d\") + timedelta(days=1)\n        data[\"yield\"] = float(split[1])\n        data.Value = float(split[1])\n\n        return data\n\n\n# Quandl \"value\" data\nclass QuandlValue(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = \"Value\"\n"
  },
  {
    "path": "static/strategies/fx-carry-trade.py",
    "content": "# region imports\nfrom AlgorithmImports import *\n\n# endregion\n# Quandl \"value\" data\nclass QuandlValue(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = \"Value\"\n\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\";\")\n\n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data[\"back_adjusted\"] = float(split[1])\n        data[\"spliced\"] = float(split[2])\n        data.Value = float(split[1])\n\n        return data\n\n\n# Custom fee model.\nclass CustomFeeModel:\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n\n\n# region imports\nfrom AlgorithmImports import *\n\n# endregion\n# https://quantpedia.com/strategies/fx-carry-trade/\n#\n# Create an investment universe consisting of several currencies (10-20). Go long three currencies with the highest central bank prime rates and\n# go short three currencies with the lowest central bank prime rates. The cash not used as the margin is invested in overnight rates. The strategy\n# is rebalanced monthly.\n\nimport data_tools\n\n\nclass ForexCarryTrade(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        # Source: https://www.quandl.com/data/OECD-Organisation-for-Economic-Co-operation-and-Development\n        self.symbols = {\n            \"CME_AD1\": \"OECD/KEI_IR3TIB01_AUS_ST_M\",  # Australian Dollar Futures, Continuous Contract #1\n            \"CME_BP1\": \"OECD/KEI_IR3TIB01_GBR_ST_M\",  # British Pound Futures, Continuous Contract #1\n            \"CME_CD1\": \"OECD/KEI_IR3TIB01_CAN_ST_M\",  # Canadian Dollar Futures, Continuous Contract #1\n            \"CME_EC1\": \"OECD/KEI_IR3TIB01_EA19_ST_M\",  # Euro FX Futures, Continuous Contract #1\n            \"CME_JY1\": \"OECD/KEI_IR3TIB01_JPN_ST_M\",  # Japanese Yen Futures, Continuous Contract #1\n            \"CME_MP1\": \"OECD/KEI_IR3TIB01_MEX_ST_M\",  # Mexican Peso Futures, Continuous Contract #1\n            \"CME_NE1\": \"OECD/KEI_IR3TIB01_NZL_ST_M\",  # New Zealand Dollar Futures, Continuous Contract #1\n            \"CME_SF1\": \"SNB/ZIMOMA\",  # Swiss Franc Futures, Continuous Contract #1\n        }\n\n        for symbol, rate_symbol in self.symbols.items():\n            self.AddData(Quandl, rate_symbol, Resolution.Daily)\n\n            data = self.AddData(data_tools.QuantpediaFutures, symbol, Resolution.Daily)\n            data.SetFeeModel(data_tools.CustomFeeModel())\n            data.SetLeverage(5)\n\n        self.recent_month = -1\n\n    def OnData(self, data):\n        rebalance_flag: bool = False\n        rate: dict[str, float] = {}\n\n        for symbol, int_rate in self.symbols.items():\n            # futures data is present in the algorithm\n            if symbol in data and data[symbol]:\n                if self.recent_month != self.Time.month:\n                    rebalance_flag = True\n                    self.recent_month = self.Time.month\n\n                # IR data is still coming in\n                if (\n                    self.Securities[int_rate].GetLastData()\n                    and (\n                        self.Time.date()\n                        - self.Securities[int_rate].GetLastData().Time.date()\n                    ).days\n                    <= 31\n                ):\n                    rate[symbol] = self.Securities[int_rate].Price\n\n        if rebalance_flag:\n            long = []\n            short = []\n            if len(rate) >= 3:\n                # interbank rate sorting\n                sorted_by_rate = sorted(rate.items(), key=lambda x: x[1], reverse=True)\n                traded_count = 3\n                long = [x[0] for x in sorted_by_rate[:traded_count]]\n                short = [x[0] for x in sorted_by_rate[-traded_count:]]\n\n            # trade execution\n            invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]\n            for symbol in invested:\n                if symbol not in long + short:\n                    self.Liquidate(symbol)\n\n            for symbol in long:\n                self.SetHoldings(symbol, 1 / len(long))\n            for symbol in short:\n                self.SetHoldings(symbol, -1 / len(short))\n"
  },
  {
    "path": "static/strategies/how-to-use-lexical-density-of-company-filings.py",
    "content": "from QuantConnect.DataSource import *\nimport numpy as np\nfrom enum import Enum\n\nclass BrainLanguageMetrics(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2010, 1, 1)\n        self.init_cash = 100000\n        self.SetCash(self.init_cash)\n\n        self.market = self.AddEquity('SPY', Resolution.Daily).Symbol\n        self.mkt = [] # benchmark chart data\n        \n        # metric dictionary with signal optimism flag\n        # metric_dictionary:dict[int, (str, bool)] = {\n        #     # 1 : ('SentenceCount', True),\n        #     # 2 : ('MeanSentenceLength', True),\n        #     # 3 : ('Sentiment', True),\n        #     # 4 : ('Uncertainty', False),\n        #     # 5 : ('Litigious', False),\n        #     # 6 : ('Constraining', False),\n        #     # 7 : ('Interesting', True),\n        #     # 8 : ('Readability', True),\n        #     9 : ('LexicalRichness', True),\n        #     10 : ('LexicalDensity', True),\n        #     11 : ('SpecificDensity', True),\n        #     12 : ('SPY', True),\n        # }\n    \n        self.metric_values = [\n            #'LexicalRichness',  #9\n            'LexicalDensity',   #10\n            'SpecificDensity'   #11\n            ]\n        \n        # opt parameters\n        # self.metric_property:tuple = metric_dictionary[int(self.GetParameter(\"metric\"))]\n        # self.metric_property:tuple = metric_dictionary[11]\n        \n        # self.portfolio_size_property:int = int(self.GetParameter(\"portfolio_size\"))\n        self.portfolio_size_property:int = 10\n        \n        # self.universe_size_property:int = int(self.GetParameter(\"universe_size\"))\n        self.universe_size_property:int = 500\n        \n        # self.long = []\n        # self.short = []\n        self.traded_quantity = {}\n        \n        self.metric = {}\n        self.metric_symbols = {}\n        self.price = {}\n        \n        self.recent_universe = []\n        \n        self.coarse_count = self.universe_size_property\n        \n        self.selection_flag = False\n        self.rebalance_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(self.DateRules.MonthStart(self.market), self.TimeRules.AfterMarketOpen(self.market), self.Selection)\n        # self.Schedule.On(self.DateRules.EveryDay(self.market), self.TimeRules.AfterMarketOpen(self.market), self.PrintBenchmark)\n        \n    def PrintBenchmark(self):\n        mkt_price = self.History(self.market, 2, Resolution.Daily)['close'].unstack(level=0).iloc[-1]\n        self.mkt.append(mkt_price)\n        mkt_perf = self.init_cash * self.mkt[-1] / self.mkt[0] \n        self.Plot('Strategy Equity', self.market, mkt_perf)\n        \n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel(self))\n            security.SetLeverage(10)\n\n        # remove recently stored metric value\n        for security in changes.RemovedSecurities:\n            symbol = security.Symbol\n            if symbol in self.metric:\n                del self.metric[symbol]\n\n    def CoarseSelectionFunction(self, coarse):\n        # return old universe if selection is not needed\n        if self.rebalance_flag and not self.selection_flag:\n            for stock in coarse:\n                symbol = stock.Symbol\n                if symbol in self.recent_universe:\n                    self.price[symbol] = stock.AdjustedPrice\n            \n            return self.recent_universe\n        \n        if not self.selection_flag:\n            return Universe.Unchanged\n        self.selection_flag = False\n        \n        if self.universe_size_property == 500 or self.universe_size_property == 1000:\n            # select top n stocks by dollar volume\n            selected = [x for x in sorted([x for x in coarse if x.HasFundamentalData],\n                    key = lambda x: x.DollarVolume, reverse = True)[:self.coarse_count]]\n        elif self.universe_size_property == 3000:\n            selected = [x for x in coarse if x.HasFundamentalData]\n            \n        for stock in selected:\n            symbol = stock.Symbol\n            self.price[symbol] = stock.AdjustedPrice\n                \n            if symbol in self.metric:\n                continue\n            \n            # create RollingWindow for specific stock symbol\n            # self.metric[symbol] = RollingWindow[float](self.period)\n            self.metric[symbol] = None\n            \n            # subscribe to Brain Language Metrics data\n            dataset_symbol = self.AddData(BrainCompanyFilingLanguageMetrics10K , symbol).Symbol\n            \n            # warmup Brain Language Metrics data\n            history = self.History(dataset_symbol, 3*30, Resolution.Daily)\n            # self.Debug(f\"We got {len(history)} items from our history request for {dataset_symbol}\")\n            \n            if not history.empty:\n                metrics = []\n                for metric_value in self.metric_values:\n                    m = getattr(history['reportsentiment'].iloc[-1], metric_value)\n                    metrics.append(m)\n                \n                # sent = history['reportsentiment'].iloc[-1].Sentiment\n                self.metric[symbol] = (history.iloc[-1].reportdate, metrics[0], metrics[1])#, metrics[2])\n            \n            # store metric symbol under stock symbol\n            self.metric_symbols[symbol] = dataset_symbol\n        \n        # return stock, which have short interest data ready\n        return [x.Symbol for x in selected if x.Symbol in self.metric and x.Symbol in self.price]\n        \n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0\n                                and ((x.SecurityReference.ExchangeId == \"NYS\")\n                                or (x.SecurityReference.ExchangeId == \"NAS\")\n                                or (x.SecurityReference.ExchangeId == \"ASE\"))]\n        \n        if self.universe_size_property == 3000:\n            fine = sorted(fine, key = lambda x:x.MarketCap, reverse=True)[:self.coarse_count]\n        \n        self.recent_universe = [x.Symbol for x in fine]\n        \n        metric_cnt = len(self.metric_values)\n        for ms_i in range(metric_cnt):\n            metric = { stock.Symbol : self.metric[stock.Symbol][ms_i+1] for stock in fine   \\\n                    if stock.Symbol in self.metric and  \\\n                    self.metric[stock.Symbol] is not None and   \\\n                    self.metric[stock.Symbol][ms_i+1] is not None and \\\n                    (self.Time - self.metric[stock.Symbol][0]).days <= 30\n            }\n        \n            if len(metric) < self.portfolio_size_property:\n                continue\n            \n            # sorting by metric\n            sorted_by_metric = sorted(metric.items(), key = lambda x: x[1], reverse=True)\n            percentile = int(len(sorted_by_metric) / self.portfolio_size_property)\n\n            long = [x[0] for x in sorted_by_metric[:percentile]]\n            short = [x[0] for x in sorted_by_metric[-percentile:]]\n            \n            # calculate quantity for every stock in every portfolio\n            long_cnt = len(long)\n            short_cnt = len(short)\n            for symbol in long:\n                q = int(((self.Portfolio.TotalPortfolioValue / metric_cnt) / long_cnt) / self.price[symbol])\n                if symbol not in self.traded_quantity:\n                    self.traded_quantity[symbol] = 0\n                self.traded_quantity[symbol] += q\n            for symbol in short:\n                q = -int(((self.Portfolio.TotalPortfolioValue / metric_cnt) / short_cnt) / self.price[symbol])\n                if symbol not in self.traded_quantity:\n                    self.traded_quantity[symbol] = 0\n                self.traded_quantity[symbol] += q\n        \n            # self.short = []\n            # self.long = []\n        \n        return list(self.traded_quantity.keys())\n\n    def OnData(self, data):\n        # update metric value for each stock\n        for stock_symbol, metric_symbol in self.metric_symbols.items():\n            # check if there are data for subscribed metric_symbol\n            if metric_symbol in data and data[metric_symbol]:\n                metrics = []\n                for metric_value in self.metric_values:\n                    m = getattr(data[metric_symbol].ReportSentiment, metric_value)\n                    metrics.append(m)\n                # sent = data[metric_symbol].ReportSentiment.Sentiment\n                \n                # update metric value for specific stock\n                self.metric[stock_symbol] = (self.Time, metrics[0], metrics[1])#, metrics[2])\n        \n        # monthly rebalance\n        if not self.rebalance_flag:\n            return\n        self.rebalance_flag = False\n        \n        if self.universe_size_property == 3000:\n            if self.Time.year in [2014, 2016] and self.Time.month == 6:\n                self.Liquidate()\n                return\n        \n        self.Liquidate()\n        \n        for symbol, q in self.traded_quantity.items():\n            if q != 0:\n                self.MarketOrder(symbol, q)\n            \n        # long_c = len(self.long)\n        # short_c = len(self.short)\n        # for symbol in self.long:\n        #     self.SetHoldings(symbol, 1/long_c)\n        # for symbol in self.short:\n        #     self.SetHoldings(symbol, -1/short_c)\n            \n        # self.weight.clear()\n        # self.long.clear()\n        # self.short.clear()\n        self.traded_quantity.clear()\n        \n    def Selection(self):\n        # if metric is market, hold SPY only without rebalance and selection\n        # if self.metric_property[0] == self.market.Value:\n        #     if not self.Portfolio[self.market].Invested:\n        #         self.SetHoldings(self.market, 1)\n        # else:\n        # new universe selection every three months\n       \n        if self.Time.month % 3 == 0:\n            self.selection_flag = True\n        \n        # rebalance once a month\n        self.rebalance_flag = True\n\n# Custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n\n# Quandl short interest data.\nclass QuandlShortVolume(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = 'SHORTVOLUME'    # also 'TOTALVOLUME' is accesible"
  },
  {
    "path": "static/strategies/intraday-seasonality-in-bitcoin.py",
    "content": "# https://quantpedia.com/strategies/intraday-seasonality-in-bitcoin/\n#\n# The investment universe consists of Bitcoin and the data are obtained from Gemini exchange. To exploit the seasonality, open a long position in the BTC at 22:00 (UTC +0) and hold it for two hours. The position is closed after the two hour holding period.\n#\n# QC implementation changes:\n#   - BTC data are obtained from Bitfinex exchange.\n\n# region imports\nfrom AlgorithmImports import *\n# endregion\n\nclass OvernightSeasonalityinBitcoin(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2016, 1, 1)\n        self.SetCash(100000)\n        \n        # NOTE Coinbase Pro, CoinAPI, and Bitfinex data is all set in UTC Time. This means that when accessing data from this brokerage, all data will be time stamped in UTC Time.\n        self.crypto = self.AddCrypto(\"BTCUSD\", Resolution.Minute, Market.Bitfinex)\n        self.crypto.SetLeverage(10)\n        self.crypto.SetFeeModel(CustomFeeModel())\n        self.crypto = self.crypto.Symbol\n\n        self.open_trade_hour:int = 22\n        self.close_trade_hour:int = 0\n\n    def OnData(self, data):\n        if self.crypto in data and data[self.crypto]:\n            time:datetime.datetime = self.UtcTime\n\n            # open long position\n            if time.hour == self.open_trade_hour and time.minute == 0:\n                self.SetHoldings(self.crypto, 1)\n            \n        # close position\n        if time.hour == self.close_trade_hour and time.minute == 0:\n            if self.Portfolio[self.crypto].Invested:\n                self.Liquidate(self.crypto)\n\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/january-barometer.py",
    "content": "# https://quantpedia.com/strategies/january-barometer/\n#\n# Invest in the equity market in each January. Stay invested in equity markets (via ETF, fund, or futures) only if January return is positive; otherwise, switch investments to T-Bills.\n\nfrom AlgorithmImports import *\n\n\nclass JanuaryBarometer(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        data = self.AddEquity(\"SPY\", Resolution.Daily)\n        data.SetLeverage(10)\n        self.market = data.Symbol\n\n        data = self.AddEquity(\"BIL\", Resolution.Daily)\n        data.SetLeverage(10)\n        self.t_bills = data.Symbol\n\n        self.start_price = None\n        self.recent_month = -1\n\n    def OnData(self, data):\n        if self.recent_month == self.Time.month:\n            return\n        self.recent_month = self.Time.month\n\n        if (\n            self.Securities[self.market].GetLastData()\n            and self.Securities[self.t_bills].GetLastData()\n        ):\n            if (\n                self.Time.date()\n                - self.Securities[self.market].GetLastData().Time.date()\n            ).days < 5 and (\n                self.Time.date()\n                - self.Securities[self.t_bills].GetLastData().Time.date()\n            ).days < 5:\n                if self.Time.month == 1:\n                    self.Liquidate(self.t_bills)\n                    self.SetHoldings(self.market, 1)\n\n                    self.start_price = self.Securities[self.market].Price\n\n                if self.Time.month == 2 and self.start_price:\n                    returns = (\n                        self.Securities[self.market].Price - self.start_price\n                    ) / self.start_price\n                    if returns > 0:\n                        self.SetHoldings(self.market, 1)\n                    else:\n                        self.start_price = None\n                        self.Liquidate(self.market)\n                        self.SetHoldings(self.t_bills, 1)\n            else:\n                self.Liquidate()\n        else:\n            self.Liquidate()\n"
  },
  {
    "path": "static/strategies/low-volatility-factor-effect-in-stocks.py",
    "content": "#region imports\nfrom AlgorithmImports import *\n#endregion\n# https://quantpedia.com/strategies/low-volatility-factor-effect-in-stocks-long-only-version/\n#\n# The investment universe consists of global large-cap stocks (or US large-cap stocks). At the end of each month, the investor constructs \n# equally weighted decile portfolios by ranking the stocks on the past three-year volatility of weekly returns. The investor goes long \n# stocks in the top decile (stocks with the lowest volatility).\n#\n# QC implementation changes:\n#   - Top quartile (stocks with the lowest volatility) is selected instead of decile.\n\nimport numpy as np\n\nclass LowVolatilityFactorEffectStocks(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)  \n        self.SetCash(100000) \n\n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        \n        self.period = 12*21\n        \n        self.coarse_count = 3000\n        self.last_coarse = []\n        self.data = {}\n        \n        self.long = []\n\n        self.selection_flag = True\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(self.DateRules.MonthEnd(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Selection)\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(10)\n            \n    def CoarseSelectionFunction(self, coarse):\n        # Update the rolling window every day.\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            # Store daily price.\n            if symbol in self.data:\n                self.data[symbol].update(stock.AdjustedPrice)\n\n        if not self.selection_flag:\n            return Universe.Unchanged\n\n        selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa']\n        # selected = [x.Symbol\n        #     for x in sorted([x for x in coarse if x.HasFundamentalData and x.Market == 'usa'],\n        #         key = lambda x: x.DollarVolume, reverse = True)[:self.coarse_count]]\n        \n        # Warmup price rolling windows.\n        for symbol in selected:\n            if symbol in self.data:\n                continue\n            \n            self.data[symbol] = SymbolData(self.period)\n            history = self.History(symbol, self.period, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet.\")\n                continue\n            closes = history.loc[symbol].close\n            for time, close in closes.iteritems():\n                self.data[symbol].update(close)\n        \n        return [x for x in selected if self.data[x].is_ready()]\n\n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0]\n        \n        # market cap sorting\n        if len(fine) > self.coarse_count:\n            sorted_by_market_cap = sorted(fine, key = lambda x: x.MarketCap, reverse=True)\n            fine = sorted_by_market_cap[:self.coarse_count]\n        \n        weekly_vol = {x.Symbol : self.data[x.Symbol].volatility() for x in fine}\n        \n        # volatility sorting\n        sorted_by_vol = sorted(weekly_vol.items(), key = lambda x: x[1], reverse = True)\n        quartile = int(len(sorted_by_vol) / 4)\n        self.long = [x[0] for x in sorted_by_vol[-quartile:]]\n        \n        return self.long\n        \n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n\n        # Trade execution.\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.long:\n                self.Liquidate(symbol)\n\n        for symbol in self.long:\n            if symbol in data and data[symbol]:\n                self.SetHoldings(symbol, 1 / len(self.long))\n\n        self.long.clear()\n        \n    def Selection(self):\n        self.selection_flag = True\n\nclass SymbolData():\n    def __init__(self, period):\n        self.price = RollingWindow[float](period)\n    \n    def update(self, value):\n        self.price.Add(value)\n    \n    def is_ready(self) -> bool:\n        return self.price.IsReady\n        \n    def volatility(self) -> float:\n        closes = [x for x in self.price]\n        \n        # Weekly volatility calc.\n        separete_weeks = [closes[x:x+5] for x in range(0, len(closes), 5)]\n        weekly_returns = [(x[0] - x[-1]) / x[-1] for x in separete_weeks]\n        return np.std(weekly_returns)   \n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/market-sentiment-and-an-overnight-anomaly.py",
    "content": "# https://quantpedia.com/strategies/market-sentiment-and-an-overnight-anomaly/\n#\n# The investment universe consists of SPY ETF, and the price of SPY, price of VIX and Brain Market Sentiment (BMS) indicator\n# are used to identify the market sentiment. The investor buys SPY ETF and holds it overnight; when the price of SPY is above its 20-day moving average,\n# the price of VIX is below its moving average, and the value of the BMS indicator is greater than its 20-day moving average.\n# Note that the authors suggest using this strategy as an overlay when deciding whether to make a trade rather than using this system on its own.\n#\n# QC Implementation:\n\n# region imports\nfrom AlgorithmImports import *\n\n# endregion\n\n\nclass MarketSentimentAndAnOvernightAnomaly(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.period: int = 20  # sma period\n\n        self.weight: float = 0\n        self.price_data: dict = {}\n\n        self.spy_symbol: Symbol = self.AddEquity(\"SPY\", Resolution.Minute).Symbol\n        self.vix_symbol: Symbol = self.AddData(\n            QuandlVix, \"CBOE/VIX\", Resolution.Daily\n        ).Symbol  # starts in 2004\n        self.bms_symbol: Symbol = self.AddData(\n            QuantpediaBMS, \"BMS_GLOBAL\", Resolution.Daily\n        ).Symbol  # starts in 2018\n\n        for symbol in [self.spy_symbol, self.vix_symbol, self.bms_symbol]:\n            self.price_data[symbol] = RollingWindow[float](self.period)\n\n    def OnData(self, data: Slice):\n        # calculate signal from SPY 16 minutes before close\n        if (\n            self.spy_symbol in data\n            and data[self.spy_symbol]\n            and self.Time.hour == 15\n            and self.Time.minute == 44\n        ):\n            weight: float = 0.0\n\n            for symbol in [self.spy_symbol, self.vix_symbol, self.bms_symbol]:\n                # trade only sub-strategies with underlying data available\n                if (\n                    self.Securities[symbol].GetLastData()\n                    and (\n                        self.Time.date()\n                        - self.Securities[symbol].GetLastData().Time.date()\n                    ).days\n                    <= 3\n                ):\n                    price: float = self.Securities[symbol].GetLastData().Price\n                    rolling_window: RollingWindow = self.price_data[symbol]\n                    if rolling_window.IsReady and self.GetSignal(\n                        price,\n                        rolling_window,\n                        True if symbol != self.vix_symbol else False,\n                    ):\n                        weight += 1 / 3\n\n                    rolling_window.Add(price)\n\n            q: int = int(\n                (self.Portfolio.TotalPortfolioValue * weight)\n                / data[self.spy_symbol].Value\n            )\n            if q != 0:\n                self.MarketOnCloseOrder(self.spy_symbol, q)\n                self.MarketOnOpenOrder(self.spy_symbol, -q)\n\n    def GetSignal(\n        self, curr_value: float, rolling_window: RollingWindow, signal_above_sma: bool\n    ) -> bool:\n        prices: list[float] = [x for x in rolling_window]\n        moving_average: float = sum(prices) / len(prices)\n\n        result: bool = False\n        if signal_above_sma and (curr_value > moving_average):\n            result = True\n        elif not signal_above_sma and (curr_value < moving_average):\n            result = True\n\n        return result\n\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaBMS(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/index/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data: QuantpediaBMS = QuantpediaBMS()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n\n        split: list = line.split(\",\")\n\n        data.Time = datetime.strptime(split[0], \"%Y-%m-%d\") + timedelta(days=1)\n        data.Value = float(split[2])\n\n        return data\n\n\nclass QuandlVix(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = \"VIX Close\"\n"
  },
  {
    "path": "static/strategies/momentum-and-reversal-combined-with-volatility-effect-in-stocks.py",
    "content": "# https://quantpedia.com/strategies/momentum-and-reversal-combined-with-volatility-effect-in-stocks/\n#\n# The investment universe consists of NYSE, AMEX, and NASDAQ stocks with prices higher than $5 per share. At the beginning of each month, \n# the sample is divided into equal halves, at the size median, and only larger stocks are used. Then each month, realized returns and realized \n# (annualized) volatilities are calculated for each stock for the past six months. One week (seven calendar days) prior to the beginning of \n# each month is skipped to avoid biases due to microstructures. Stocks are then sorted into quintiles based on their realized past returns \n# and past volatility. The investor goes long on stocks from the highest performing quintile from the highest volatility group and short on \n# stocks from the lowest-performing quintile from the highest volatility group. Stocks are equally weighted and held for six months \n# (therefore, 1/6 of the portfolio is rebalanced every month).\n#\n# QC implementation changes:\n#   - Instead of all listed stock, we select 1000 most liquid stocks from QC filtered stock universe (~8000 stocks) due to time complexity issues tied to whole universe filtering.\n    \nimport numpy as np\nfrom AlgorithmImports import *\n\nclass MomentumReversalCombinedWithVolatilityEffectinStocks(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2002, 1, 1)\n        self.SetCash(100000)\n\n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        \n        # EW Tranching.\n        self.holding_period = 6\n        self.managed_queue = []\n\n        # Daily price data.\n        self.data = {}\n        self.period = 6 * 21\n        \n        self.coarse_count = 1000\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(self.DateRules.MonthStart(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Selection)\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(10)\n            \n    def CoarseSelectionFunction(self, coarse):\n        # Update the rolling window every day.\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            # Store monthly price.\n            if symbol in self.data:\n                self.data[symbol].update(stock.AdjustedPrice)\n                self.data[symbol].LastPrice = stock.AdjustedPrice\n\n        if not self.selection_flag:\n            return Universe.Unchanged\n        \n        # selected = [x for x in coarse if x.HasFundamentalData and x.Market == 'usa' and x.Price > 5]\n        selected = sorted([x for x in coarse if x.HasFundamentalData and x.Market == 'usa' and x.Price > 5],    \\\n                key = lambda x: x.DollarVolume, reverse = True)[:self.coarse_count]\n        \n        # Warmup price rolling windows.\n        for stock in selected:\n            symbol = stock.Symbol\n            if symbol in self.data:\n                continue\n            \n            self.data[symbol] = SymbolData(symbol, self.period)\n            history = self.History(symbol, self.period, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet.\")\n                continue\n            closes = history.loc[symbol].close\n            for time, close in closes.iteritems():\n                self.data[symbol].update(close)\n                self.data[symbol].LastPrice = close\n                \n        return [x.Symbol for x in selected if self.data[x.Symbol].is_ready()]\n\n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0 and \\\n                    ((x.SecurityReference.ExchangeId == \"NYS\") or (x.SecurityReference.ExchangeId == \"NAS\") or (x.SecurityReference.ExchangeId == \"ASE\"))]\n\n        # if len(fine) > self.coarse_count:\n        #     sorted_by_market_cap = sorted(fine, key = lambda x: x.MarketCap, reverse=True)\n        #     top_by_market_cap = sorted_by_market_cap[:self.coarse_count]\n        # else:\n        #     top_by_market_cap = fine\n            \n        sorted_by_market_cap = sorted(fine, key = lambda x: x.MarketCap, reverse=True)\n        half = int(len(sorted_by_market_cap) / 2)\n        top_by_market_cap = [x.Symbol for x in sorted_by_market_cap][:half]\n        \n        # Performance and volatility tuple.\n        perf_volatility = {}\n        for symbol in top_by_market_cap:\n            performance = self.data[symbol].performance()\n            annualized_volatility = self.data[symbol].volatility()\n            perf_volatility[symbol] = (performance, annualized_volatility)\n        \n        long = []\n        short = []\n        if len(perf_volatility) >= 5:\n            sorted_by_perf = sorted(perf_volatility.items(), key = lambda x: x[1][0], reverse = True)\n            quintile = int(len(sorted_by_perf) / 5)\n            top_by_perf = [x[0] for x in sorted_by_perf[:quintile]]\n            low_by_perf = [x[0] for x in sorted_by_perf[-quintile:]]\n            \n            sorted_by_vol = sorted(perf_volatility.items(), key = lambda x: x[1][1], reverse = True)\n            quintile = int(len(sorted_by_vol) / 5)\n            top_by_vol = [x[0] for x in sorted_by_vol[:quintile]]\n            low_by_vol = [x[0] for x in sorted_by_vol[-quintile:]]\n            \n            long = [x for x in top_by_perf if x in top_by_vol]\n            short = [x for x in low_by_perf if x in top_by_vol]\n\n        if len(long) != 0:\n            long_w = self.Portfolio.TotalPortfolioValue / self.holding_period / len(long)\n            # symbol/quantity collection\n            long_symbol_q = [(x, np.ceil(long_w / self.data[x].LastPrice)) for x in long]\n        else:\n            long_symbol_q = []\n    \n        if len(short) != 0:\n            short_w = self.Portfolio.TotalPortfolioValue / self.holding_period / len(short)\n            # symbol/quantity collection\n            short_symbol_q = [(x, -np.ceil(short_w / self.data[x].LastPrice)) for x in short]\n        else:\n            short_symbol_q = []\n                \n        self.managed_queue.append(RebalanceQueueItem(long_symbol_q + short_symbol_q))\n        \n        return long + short\n        \n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n       \n        remove_item = None\n        \n        # Rebalance portfolio\n        for item in self.managed_queue:\n            if item.holding_period == self.holding_period:\n                for symbol, quantity in item.symbol_q:\n                    if self.Securities[symbol].Price != 0 and self.Securities[symbol].IsTradable:\n                        self.MarketOrder(symbol, -quantity)\n                \n                remove_item = item\n            \n            # Trade execution    \n            if item.holding_period == 0:\n                open_symbol_q = []\n                \n                for symbol, quantity in item.symbol_q:\n                    if self.Securities[symbol].Price != 0 and self.Securities[symbol].IsTradable:\n                        self.MarketOrder(symbol, quantity)\n                        open_symbol_q.append((symbol, quantity))\n                            \n                # Only opened orders will be closed        \n                item.symbol_q = open_symbol_q\n                \n            item.holding_period += 1\n            \n        # We need to remove closed part of portfolio after loop. Otherwise it will miss one item in self.managed_queue.\n        if remove_item:\n            self.managed_queue.remove(remove_item)\n    \n    def Selection(self):\n        self.selection_flag = True\n\nclass RebalanceQueueItem():\n    def __init__(self, symbol_q):\n        # symbol/quantity collections\n        self.symbol_q = symbol_q  \n        self.holding_period = 0\n\nclass SymbolData():\n    def __init__(self, symbol, period):\n        self.Symbol = symbol\n        self.Price = RollingWindow[float](period)\n        self.LastPrice = 0\n    \n    def update(self, value):\n        self.Price.Add(value)\n    \n    def is_ready(self):\n        return self.Price.IsReady\n    \n    def update(self, close):\n        self.Price.Add(close)\n        \n    def volatility(self):\n        closes = np.array([x for x in self.Price][5:]) # Skip last week.\n        daily_returns = closes[:-1] / closes[1:] - 1\n        return np.std(daily_returns) * np.sqrt(252 / (len(closes)))\n        \n    def performance(self):\n        closes = [x for x in self.Price][5:] # Skip last week.\n        return (closes[0] / closes[-1] - 1)\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/momentum-effect-in-commodities.py",
    "content": "#region imports\nfrom AlgorithmImports import *\n#endregion\n# https://quantpedia.com/strategies/1-month-momentum-in-commodities/\n#\n# Create a universe of tradable commodity futures. Rank futures performance for each commodity for the last 12 months and divide them into quintiles. \n# Go long on the quintile with the highest momentum and go short on the quintile with the lowest momentum. Rebalance each month.\n\nclass MomentumEffectCommodities(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.symbols = [\n                        \"CME_S1\",   # Soybean Futures, Continuous Contract\n                        \"CME_W1\",   # Wheat Futures, Continuous Contract\n                        \"CME_SM1\",  # Soybean Meal Futures, Continuous Contract\n                        \"CME_BO1\",  # Soybean Oil Futures, Continuous Contract\n                        \"CME_C1\",   # Corn Futures, Continuous Contract\n                        \"CME_O1\",   # Oats Futures, Continuous Contract\n                        \"CME_LC1\",  # Live Cattle Futures, Continuous Contract\n                        \"CME_FC1\",  # Feeder Cattle Futures, Continuous Contract\n                        \"CME_LN1\",  # Lean Hog Futures, Continuous Contract\n                        \"CME_GC1\",  # Gold Futures, Continuous Contract\n                        \"CME_SI1\",  # Silver Futures, Continuous Contract\n                        \"CME_PL1\",  # Platinum Futures, Continuous Contract\n                        \"CME_CL1\",  # Crude Oil Futures, Continuous Contract\n                        \"CME_HG1\",  # Copper Futures, Continuous Contract\n                        \"CME_LB1\",  # Random Length Lumber Futures, Continuous Contract\n                        \"CME_NG1\",  # Natural Gas (Henry Hub) Physical Futures, Continuous Contract\n                        \"CME_PA1\",  # Palladium Futures, Continuous Contract \n                        \"CME_RR1\",  # Rough Rice Futures, Continuous Contract\n                        \"CME_DA1\",  # Class III Milk Futures\n                        \"ICE_RS1\",  # Canola Futures, Continuous Contract\n                        \"ICE_GO1\",  # Gas Oil Futures, Continuous Contract\n                        \"CME_RB2\",  # Gasoline Futures, Continuous Contract\n                        \"CME_KW2\",  # Wheat Kansas, Continuous Contract\n                        \"ICE_WT1\",  # WTI Crude Futures, Continuous Contract\n                        \n                        \"ICE_CC1\",  # Cocoa Futures, Continuous Contract \n                        \"ICE_CT1\",  # Cotton No. 2 Futures, Continuous Contract\n                        \"ICE_KC1\",  # Coffee C Futures, Continuous Contract\n                        \"ICE_O1\",   # Heating Oil Futures, Continuous Contract\n                        \"ICE_OJ1\",  # Orange Juice Futures, Continuous Contract\n                        \"ICE_SB1\",  # Sugar No. 11 Futures, Continuous Contract\n                        ]\n        \n        self.period = 12 * 21\n        self.SetWarmUp(self.period, Resolution.Daily)\n        self.data = {}\n        \n        for symbol in self.symbols:\n            data = self.AddData(QuantpediaFutures, symbol, Resolution.Daily)\n            data.SetFeeModel(CustomFeeModel())\n            data.SetLeverage(5)\n            self.data[symbol] = self.ROC(symbol, self.period, Resolution.Daily)\n        \n        self.recent_month = -1\n\n    def OnData(self, data):\n        if self.IsWarmingUp:\n            return\n\n        # rebalance once a month\n        if self.recent_month == self.Time.month:\n            return\n        self.recent_month = self.Time.month\n\n        perf = { x[0] : x[1].Current.Value for x in self.data.items() if self.data[x[0]].IsReady and x[0] in data and data[x[0]] }\n\n        long = []\n        short = []\n        if len(perf) >= 5:\n            sorted_by_performance = sorted(perf.items(), key = lambda x:x[1], reverse=True)\n            quintile = int(len(sorted_by_performance) / 5)\n            long = [x[0] for x in sorted_by_performance[:quintile]]\n            short = [x[0] for x in sorted_by_performance[-quintile:]]\n\n        # trade execution\n        invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]\n        for symbol in invested:\n            if symbol not in long + short:\n                self.Liquidate(symbol)\n                \n        for symbol in long:\n            self.SetHoldings(symbol, 1 / len(long))\n        for symbol in short:\n            self.SetHoldings(symbol, -1 / len(short))\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n        split = line.split(';')\n        \n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data['back_adjusted'] = float(split[1])\n        data['spliced'] = float(split[2])\n        data.Value = float(split[1])\n\n        return data\n\n# Custom fee model.\nclass CustomFeeModel():\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/momentum-factor-and-style-rotation-effect.py",
    "content": "#region imports\nfrom AlgorithmImports import *\n#endregion\n# https://quantpedia.com/strategies/momentum-factor-and-style-rotation-effect/\n# \n# Russell’s ETFs for six equity styles are used\n# (small-cap value, mid-cap value, large-cap value, small-cap growth, mid-cap growth, large-cap growth).\n# Each month, the investor calculates 12-month momentum for each style and goes long on the winner and short on the loser.\n# The portfolio is rebalanced each month.\n#\n# QC Implementation:\n#   - Trading IVW in 10/2020 is skipped due to data error.\n\nclass MomentumFactorAndStyleRotationEffect(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n        \n        self.tickers = [\n            'IWS', # iShares Russell Midcap Value ETF\n            'IWP', # iShares Russell Midcap Growth ETF\n            'IWN', # iShares Russell 2000 Value ETF\n            'IWO', # iShares Russell 2000 Growth ETF\n            'IVE', # iShares S&P 500 Value ETF\n            'IVW'  # iShares S&P 500 Growth ETF       \n        ]\n        \n        self.mom = {}\n        \n        self.period = 12 * 21\n        self.SetWarmUp(self.period)\n        \n        for ticker in self.tickers:\n            security = self.AddEquity(ticker, Resolution.Daily)\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(10)\n            \n            self.mom[security.Symbol] = self.MOM(security.Symbol, self.period)\n        \n        self.recent_month = -1\n        \n    def OnData(self, data):\n        if self.recent_month == self.Time.month:\n            return\n        self.recent_month = self.Time.month\n        \n        mom_ready = [ s for s in self.mom if self.mom[s].IsReady and s in data]\n        if mom_ready:\n            sorted_mom = sorted(mom_ready, key = lambda x: self.mom[x].Current.Value, reverse=True)\n            \n            for symbol in sorted_mom[1:-1]:\n                if self.Portfolio[symbol].Invested:\n                    self.Liquidate(symbol)\n            \n            winner = sorted_mom[0]\n            loser = sorted_mom[-1]\n            \n            if self.Securities[winner].Price != 0 and self.Securities[winner].IsTradable:\n                if (self.Time.month == 10 and self.Time.year == 2020) and winner.Value == 'IVW':    # prevent data error\n                    self.Liquidate(winner)\n                else:\n                    self.SetHoldings(winner, 1)\n            \n            if self.Securities[loser].Price != 0 and self.Securities[loser].IsTradable:\n                if (self.Time.month == 10 and self.Time.year == 2020) and loser.Value == 'IVW':     # prevent data error\n                    self.Liquidate(loser)\n                else:\n                    self.SetHoldings(loser, -1)\n        \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/momentum-factor-combined-with-asset-growth-effect.py",
    "content": "# https://quantpedia.com/strategies/momentum-factor-combined-with-asset-growth-effect/\n#\n# The investment universe consists of NYSE, AMEX and NASDAQ stocks (data for the backtest in the source paper are from Compustat). \n# Stocks with a market capitalization less than the 20th NYSE percentile (smallest stocks) are removed. The asset growth variable \n# is defined as the yearly percentage change in balance sheet total assets. Data from year t-2 to t-1 are used to calculate asset\n# growth, and July is the cut-off month. Every month, stocks are then sorted into deciles based on asset growth and only stocks \n# with the highest asset growth are used. The next step is to sort stocks from the highest asset growth decile into quintiles, \n# based on their past 11-month return (with the last month’s performance skipped in the calculation). The investor then goes long\n# on stocks with the strongest momentum and short on stocks with the weakest momentum. The portfolio is equally weighted and is\n# rebalanced monthly. The investor holds long-short portfolios only during February-December -> January is excluded as this month\n# has been repeatedly documented as a negative month for a momentum strategy (see “January Effect Filter and Momentum in Stocks”).\n#\n# QC implementation changes:\n#   - Universe consists of 500 most liquid stocks traded on NYSE, AMEX, or NASDAQ.\n\nfrom AlgorithmImports import *\n\nclass MomentumFactorAssetGrowthEffect(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        # Monthly close data.\n        self.data = {}\n        self.period = 13\n        self.total_assets_history_period = 2\n        \n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        self.spy_consolidator = TradeBarConsolidator(timedelta(days=21))\n        self.spy_consolidator.DataConsolidated += self.CustomHandler\n        self.SubscriptionManager.AddConsolidator(self.symbol, self.spy_consolidator)            \n        \n        self.data[self.symbol] = SymbolData(self.symbol, self.period, self.total_assets_history_period)\n        # Warmup market history.\n        history = self.History(self.symbol, self.period, Resolution.Daily)\n        if not history.empty:\n            closes = history.loc[self.symbol].close\n            closes_len = len(closes.keys())\n            # Find monthly closes.\n            for index, time_close in enumerate(closes.iteritems()):\n                # index out of bounds check.\n                if index + 1 < closes_len:\n                    date_month = time_close[0].date().month\n                    next_date_month = closes.keys()[index + 1].month\n                \n                    # Found last day of month.\n                    if date_month != next_date_month:\n                        self.data[self.symbol].update(time_close[1])\n        \n        self.coarse_count = 500\n        \n        self.long = []\n        self.short = []\n\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(self.DateRules.MonthEnd(self.symbol), self.TimeRules.BeforeMarketClose(self.symbol), self.Selection)\n\n    def CustomHandler(self, sender, consolidated):\n        self.data[self.symbol].update(consolidated.Close)\n        \n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(5)\n        \n    def CoarseSelectionFunction(self, coarse):\n        if not self.selection_flag:\n            return Universe.Unchanged\n\n        # Update the rolling window every month.\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            # Store monthly price.\n            if symbol in self.data:\n                self.data[symbol].update(stock.AdjustedPrice)\n\n        # selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa']\n        selected = [x.Symbol\n            for x in sorted([x for x in coarse if x.HasFundamentalData and x.Market == 'usa'],\n                key = lambda x: x.DollarVolume, reverse = True)[:self.coarse_count]]\n        \n        # Warmup price rolling windows.\n        for symbol in selected:\n            if symbol in self.data:\n                continue\n            \n            self.data[symbol] = SymbolData(symbol, self.period, self.total_assets_history_period)\n            history = self.History(symbol, self.period, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet.\")\n                continue\n            closes = history.loc[symbol].close\n            \n            closes_len = len(closes.keys())\n            # Find monthly closes.\n            for index, time_close in enumerate(closes.iteritems()):\n                # index out of bounds check.\n                if index + 1 < closes_len:\n                    date_month = time_close[0].date().month\n                    next_date_month = closes.keys()[index + 1].month\n                \n                    # Found last day of month.\n                    if date_month != next_date_month:\n                        self.data[symbol].update(time_close[1])\n            \n        return [x for x in selected if self.data[x].is_ready()]   \n\n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.FinancialStatements.BalanceSheet.TotalAssets.TwelveMonths > 0 and \n                ((x.SecurityReference.ExchangeId == \"NYS\") or (x.SecurityReference.ExchangeId == \"NAS\") or (x.SecurityReference.ExchangeId == \"ASE\"))]\n\n        # if len(fine) > self.coarse_count:\n        #     sorted_by_market_cap = sorted(fine, key = lambda x: x.MarketCap, reverse=True)\n        #     top_by_market_cap = sorted_by_market_cap[:self.coarse_count]\n        # else:\n        #     top_by_market_cap = fine\n        \n        top_by_market_cap = fine\n        \n        # Asset growth calc.\n        asset_growth = {}\n        for stock in top_by_market_cap:\n            symbol = stock.Symbol\n\n            if self.data[symbol].asset_data_is_ready():\n                asset_growth[symbol] = self.data[symbol].asset_growth()\n                \n            self.data[symbol].update_assets(stock.FinancialStatements.BalanceSheet.TotalAssets.TwelveMonths)\n        \n        sorted_by_growth = sorted(asset_growth.items(), key = lambda x: x[1], reverse = True)\n        decile = int(len(sorted_by_growth) / 10)\n        top_by_growth = [x[0] for x in sorted_by_growth][:decile]\n        \n        performance = { x : self.data[x].performance(1) for x in top_by_growth}\n        sorted_by_performance = sorted(performance.items(), key = lambda x: x[1], reverse = True)\n        quintile = int(len(sorted_by_performance) / 5)\n        self.long = [x[0] for x in sorted_by_performance][:quintile]\n        self.short = [x[0] for x in sorted_by_performance][-quintile:]\n        \n        return self.long + self.short\n\n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n        \n        # Trade execution.\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.long + self.short:\n                self.Liquidate(symbol)\n        \n        for symbol in self.long:\n            self.SetHoldings(symbol, 1 / len(self.long))\n        for symbol in self.short:\n            self.SetHoldings(symbol, -1 / len(self.short))\n\n        self.long.clear()\n        self.short.clear()\n\n    def Selection(self):\n        # Exclude January trading.\n        if self.Time.month != 12:\n            self.selection_flag = True\n        else:\n            self.Liquidate()\n\nclass SymbolData():\n    def __init__(self, symbol, period, total_assets_history_period):\n        self.Symbol = symbol\n        self.Price = RollingWindow[float](period)\n        self.TotalAssets = RollingWindow[float](total_assets_history_period)\n    \n    def update(self, value):\n        self.Price.Add(value)\n    \n    def update_assets(self, assets_value):\n        self.TotalAssets.Add(assets_value)\n    \n    def asset_data_is_ready(self) -> bool:\n        return self.TotalAssets.IsReady\n    \n    def asset_growth(self) -> float:\n        asset_values = [x for x in self.TotalAssets]\n        return (asset_values[0] - asset_values[1]) / asset_values[1]\n    \n    def is_ready(self) -> bool:\n        return self.Price.IsReady\n        \n    # Performance, one month skipped.\n    def performance(self, values_to_skip = 0) -> float:\n        closes = [x for x in self.Price][values_to_skip:]\n        return (closes[0] / closes[-1] - 1)\n        \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/momentum-factor-effect-in-stocks.py",
    "content": "# https://quantpedia.com/strategies/momentum-factor-effect-in-stocks/\n#\n# The investment universe consists of NYSE, AMEX, and NASDAQ stocks. We define momentum as the past 12-month return, skipping the most \n# recent month’s return (to avoid microstructure and liquidity biases). To capture “momentum”, UMD portfolio goes long stocks that have \n# high relative past one-year returns and short stocks that have low relative past one-year returns.\n#\n# QC implementation changes:\n#   - Instead of all listed stock, we select top 500 stocks by market cap from QC stock universe.\n    \nfrom AlgorithmImports import *\n\nclass MomentumFactorEffectinStocks(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        \n        self.weight = {}\n        self.data = {}\n        self.period = 12 * 21\n        self.quantile = 5\n        \n        self.coarse_count = 500\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(self.DateRules.MonthStart(symbol), self.TimeRules.AfterMarketOpen(symbol), self.Selection)\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(10)\n        \n    def CoarseSelectionFunction(self, coarse):\n        # Update the rolling window every day.\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            # Store monthly price.\n            if symbol in self.data:\n                self.data[symbol].Add(stock.AdjustedPrice)\n\n        if not self.selection_flag:\n            return Universe.Unchanged\n        \n        # selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa' and x.Price > 5]\n        selected = [x.Symbol\n            for x in sorted([x for x in coarse if x.HasFundamentalData and x.Market == 'usa'],\n                key = lambda x: x.DollarVolume, reverse = True)[:self.coarse_count]]\n   \n        # Warmup price rolling windows.\n        for symbol in selected:\n            if symbol in self.data:\n                continue\n            \n            self.data[symbol] = RollingWindow[float](self.period)\n            history = self.History(symbol, self.period, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet\")\n                continue\n            closes = history.loc[symbol].close\n            for time, close in closes.iteritems():\n                self.data[symbol].Add(close)\n                \n        return [x for x in selected if self.data[x].IsReady]\n    \n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0 and \\\n                    ((x.SecurityReference.ExchangeId == \"NYS\") or (x.SecurityReference.ExchangeId == \"NAS\") or (x.SecurityReference.ExchangeId == \"ASE\"))]\n                    \n        # if len(fine) > self.coarse_count:\n        #     sorted_by_market_cap = sorted(fine, key = lambda x:x.MarketCap, reverse=True)\n        #     top_by_market_cap = [x for x in sorted_by_market_cap[:self.coarse_count]]\n        # else:\n        #     top_by_market_cap = fine\n\n        perf = {x.Symbol : self.data[x.Symbol][0] / self.data[x.Symbol][self.period-1] - 1 for x in fine}\n\n        if len(perf) >= self.quantile:\n            sorted_by_perf = sorted(perf.items(), key = lambda x:x[1], reverse=True)\n            quantile = int(len(sorted_by_perf) / self.quantile)\n            long = [x[0] for x in sorted_by_perf[:quantile]]\n            short = [x[0] for x in sorted_by_perf[-quantile:]]\n\n            long_count = len(long)\n            short_count = len(short)\n\n            for symbol in long:\n                self.weight[symbol] = 1 / long_count\n            for symbol in short:\n                self.weight[symbol] = -1 / short_count\n        \n        return list(self.weight.keys())\n        \n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n\n        # Trade execution.\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.weight:\n                self.Liquidate(symbol)\n        \n        for symbol, w in self.weight.items():\n            if symbol in data and data[symbol]:\n                self.SetHoldings(symbol, w)\n\n        self.weight.clear()\n        \n    def Selection(self):\n        self.selection_flag = True\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/momentum-in-mutual-fund-returns.py",
    "content": "# https://quantpedia.com/strategies/momentum-in-mutual-fund-returns/\n#\n# The investment universe consists of equity funds from the CRSP Mutual Fund database.\n# This universe is then shrunk to no-load funds (to remove entrance fees).\n# Investors then sort mutual funds based on their past 6-month return and divide them into deciles.\n# The top decile of mutual funds is then picked into an investment portfolio (equally weighted), and funds are held for three months.\n# Other measures of momentum could also be used in sorting (fund’s closeness to 1 year high in NAV and momentum factor loading),\n# and it is highly probable that the combined predictor would have even better results than only the simple 6-month momentum.\n#\n# QC Implementation:\n#   - Universe consist of approximately 850 mutual funds.\n\n#region imports\nfrom AlgorithmImports import *\n#endregion\n\nclass MomentuminMutualFundReturns(QCAlgorithm):\n\n    def Initialize(self):\n        # NOTE: most of the data start from 2014 and until 2015 there wasn't any trade\n        self.SetStartDate(2014, 1, 1)\n        self.SetCash(100000)\n        \n        self.data = {}\n        self.symbols = []\n        \n        self.period = 21 * 6 # Storing 6 months of daily prices\n        self.quantile = 10\n        \n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        \n        # Load csv file with etf symbols and split line with semi-colon\n        etf_symbols_csv = self.Download(\"data.quantpedia.com/backtesting_data/equity/mutual_funds/symbols.csv\")\n        splitted_csv = etf_symbols_csv.split(';')\n        \n        for symbol in splitted_csv:\n            self.symbols.append(symbol)\n            \n            # Subscribe for QuantpediaETF by etf symbol, then set fee model and leverage\n            data = self.AddData(QuantpediaETF, symbol, Resolution.Daily)\n            data.SetFeeModel(CustomFeeModel())\n            data.SetLeverage(5)\n            \n            self.data[symbol] = RollingWindow[float](self.period)\n        \n        self.recent_month = -1\n\n    def OnData(self, data):\n        # Update daily prices of etfs\n        for symbol in self.symbols:\n            if symbol in data and data[symbol]:\n                price = data[symbol].Value\n                self.data[symbol].Add(price)\n\n        if self.recent_month == self.Time.month:\n            return\n        self.recent_month = self.Time.month\n\n        # Rebalance quarterly\n        if self.recent_month % 3 != 0:\n            return\n            \n        performance = {}\n        \n        for symbol in self.symbols:\n            # If data for etf are ready calculate it's 6 month performance\n            if self.data[symbol].IsReady:\n                if self.Securities[symbol].GetLastData() and (self.Time.date() - self.Securities[symbol].GetLastData().Time.date()).days <= 3:\n                    prices = [x for x in self.data[symbol]]\n                    performance[symbol] = (prices[0] - prices[-1]) / prices[-1]\n                \n        if len(performance) < self.quantile:\n            self.Liquidate()\n            return\n        \n        decile = int(len(performance) / self.quantile)\n        # sort dictionary by performance and based on it create sorted list\n        sorted_by_perf = [x[0] for x in sorted(performance.items(), key=lambda item: item[1], reverse=True)]\n        # select top decile etfs for investment based on performance\n        long = sorted_by_perf[:decile]\n        \n        # Trade execution\n        invested_etfs = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in invested_etfs:\n            if symbol not in long:\n                self.Liquidate(symbol)\n            \n        long_length = len(long)\n        \n        for symbol in long:\n            self.SetHoldings(symbol, 1 / long_length)    \n\n# Quantpedia data\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaETF(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/equity/mutual_funds/{0}.csv\".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaETF()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n        split = line.split(';')\n        \n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data['settle'] = float(split[1])\n        data.Value = float(split[1])\n\n        return data\n\n# Custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/option-expiration-week-effect.py",
    "content": "# https://quantpedia.com/strategies/option-expiration-week-effect/\n#\n# Investors choose stocks from the S&P 100 index as his/her investment universe (stocks could be easily tracked via ETF or index fund).\n# He/she then goes long S&P 100 stocks during the option-expiration week and stays in cash during other days.\n\nfrom AlgorithmImports import *\n\nclass OptionExpirationWeekEffect(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2010, 1, 1)\n        self.SetCash(10000)\n\n        self.symbol = self.AddEquity(\"OEF\", Resolution.Minute).Symbol\n        \n        option = self.AddOption(\"OEF\")\n        option.SetFilter(-3, 3, timedelta(0), timedelta(days = 60))       \n\n        self.SetBenchmark(\"OEF\")\n        self.near_expiry = datetime.min\n        \n        self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday, DayOfWeek.Monday), self.TimeRules.AfterMarketOpen(self.symbol, 1), self.Rebalance)\n\n    def OnData(self, slice):\n        if self.Time.date() == self.near_expiry.date():\n            self.Liquidate()\n\n    def Rebalance(self):\n        calendar = self.TradingCalendar.GetDaysByType(TradingDayType.OptionExpiration, self.Time, self.EndDate)\n        expiries = [i.Date for i in calendar]\n        if len(expiries) == 0: return\n\n        self.near_expiry = expiries[0]\n\n        if (self.near_expiry - self.Time).days <= 5:\n            self.SetHoldings(self.symbol, 1)"
  },
  {
    "path": "static/strategies/paired-switching.py",
    "content": "# https://quantpedia.com/strategies/paired-switching/\n#\n# This strategy is very flexible. Investors could use stocks, funds, or ETFs as an investment vehicle. We show simple trading rules for a sample strategy\n# from the source research paper. The investor uses two Vanguard funds as his investment vehicles – one equity fund (VFINX) and one government bond\nfrom AlgorithmImports import *\n\n# fund (VUSTX). These two funds have a negative correlation as they are proxies for two negatively correlated asset classes. The investor looks at the\n# performance of the two funds over the prior quarter and buys the fund that has a higher return during the ranking period. The position is held for one\n# quarter (the investment period). At the end of the investment period, the cycle is repeated.\n\n\nclass PairedSwitching(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2004, 1, 1)\n        self.SetCash(100000)\n\n        self.first_symbol = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n        self.second_symbol = self.AddEquity(\"AGG\", Resolution.Daily).Symbol\n        self.recent_month = -1\n\n    def OnData(self, data):\n        if self.Time.month == self.recent_month:\n            return\n        self.recent_month = self.Time.month\n\n        if self.recent_month % 3 == 0:\n            if self.first_symbol in data and self.second_symbol in data:\n                history_call = self.History(\n                    [self.first_symbol, self.second_symbol], timedelta(days=90)\n                )\n                if not history_call.empty:\n                    first_bars = history_call.loc[self.first_symbol.Value]\n                    last_p1 = first_bars[\"close\"].iloc[0]\n\n                    second_bars = history_call.loc[self.second_symbol.Value]\n                    last_p2 = second_bars[\"close\"].iloc[0]\n\n                    # Calculates performance of funds over the prior quarter.\n                    first_performance = (\n                        float(self.Securities[self.first_symbol].Price) - float(last_p1)\n                    ) / (float(self.Securities[self.first_symbol].Price))\n                    second_performance = (\n                        float(self.Securities[self.second_symbol].Price)\n                        - float(last_p2)\n                    ) / (float(self.Securities[self.second_symbol].Price))\n\n                    # Buys the fund that has the higher return during the period.\n                    if first_performance > second_performance:\n                        if self.Securities[self.second_symbol].Invested:\n                            self.Liquidate(self.second_symbol)\n                        self.SetHoldings(self.first_symbol, 1)\n                    else:\n                        if self.Securities[self.first_symbol].Invested:\n                            self.Liquidate(self.first_symbol)\n                        self.SetHoldings(self.second_symbol, 1)\n"
  },
  {
    "path": "static/strategies/pairs-trading-with-country-etfs.py",
    "content": "# https://quantpedia.com/strategies/pairs-trading-with-country-etfs/\n#\n# The investment universe consists of 22 international ETFs. A normalized cumulative total return index is created for each ETF (dividends \n# included), and the starting price during the formation period is set to $1 (price normalization). The selection of pairs is made after\n# a 120 day formation period. Pair’s distance for all ETF pairs is calculated as the sum of squared deviations between two normalized \n# price series. The top 5 pairs with the smallest distance are used in the subsequent 20 day trading period. The strategy is monitored\n# daily, and trade is opened when the divergence between the pairs exceeds 0.5x the historical standard deviation. Investors go long \n# on the undervalued ETF and short on the overvalued ETF. The trade is exited if a pair converges or after 20 days (if the pair does \n# not converge within the next 20 business days). Pairs are weighted equally, and the portfolio is rebalanced on a daily basis.\n#\n# QC Implementation:\n\nimport numpy as np\nfrom AlgorithmImports import *\nimport itertools as it\n\nclass PairsTradingwithCountryETFs(QCAlgorithm):\n    \n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n       \n        self.symbols = [\n                        \"EWA\",  # iShares MSCI Australia Index ETF\n                        \"EWO\",  # iShares MSCI Austria Investable Mkt Index ETF\n                        \"EWK\",  # iShares MSCI Belgium Investable Market Index ETF\n                        \"EWZ\",  # iShares MSCI Brazil Index ETF\n                        \"EWC\",  # iShares MSCI Canada Index ETF\n                        \"FXI\",  # iShares China Large-Cap ETF\n                        \"EWQ\",  # iShares MSCI France Index ETF\n                        \"EWG\",  # iShares MSCI Germany ETF \n                        \"EWH\",  # iShares MSCI Hong Kong Index ETF\n                        \"EWI\",  # iShares MSCI Italy Index ETF\n                        \"EWJ\",  # iShares MSCI Japan Index ETF\n                        \"EWM\",  # iShares MSCI Malaysia Index ETF\n                        \"EWW\",  # iShares MSCI Mexico Inv. Mt. Idx\n                        \"EWN\",  # iShares MSCI Netherlands Index ETF\n                        \"EWS\",  # iShares MSCI Singapore Index ETF\n                        \"EZA\",  # iShares MSCI South Africe Index ETF\n                        \"EWY\",  # iShares MSCI South Korea ETF\n                        \"EWP\",  # iShares MSCI Spain Index ETF\n                        \"EWD\",  # iShares MSCI Sweden Index ETF\n                        \"EWL\",  # iShares MSCI Switzerland Index ETF\n                        \"EWT\",  # iShares MSCI Taiwan Index ETF\n                        \"THD\",  # iShares MSCI Thailand Index ETF\n                        \"EWU\",  # iShares MSCI United Kingdom Index ETF\n                        \"SPY\",  # SPDR S&P 500 ETF\n                        ]\n        \n        self.period = 120\n        self.max_traded_pairs = 5 # The top 5 pairs with the smallest distance are used.\n        \n        self.history_price = {}\n        self.traded_pairs = []\n        self.traded_quantity = {}\n\n        for symbol in self.symbols:\n            data = self.AddEquity(symbol, Resolution.Daily)\n            data.SetFeeModel(CustomFeeModel())\n            data.SetLeverage(5)\n            symbol_obj = data.Symbol\n            \n            if symbol not in self.history_price:\n                self.history_price[symbol] = RollingWindow[float](self.period)\n                \n                history = self.History(self.Symbol(symbol), self.period, Resolution.Daily)\n                if history.empty:\n                    self.Log(f\"Note enough data for {symbol} yet\")\n                else:\n                    closes = history.loc[symbol].close[:-1]\n                    for time, close in closes.iteritems():\n                        self.history_price[symbol].Add(close)\n\n        self.sorted_pairs = []\n        self.symbol_pairs = list(it.combinations(self.symbols, 2))  \n        self.days = 20\n    \n    def OnData(self, data):\n        # Update the price series everyday\n        for symbol in self.history_price:\n            symbol_obj = self.Symbol(symbol)\n            if symbol_obj in data and data[symbol_obj]:\n                price = data[symbol_obj].Value\n                self.history_price[symbol].Add(price)\n                        \n        # Start of trading period.\n        if self.days == 20:\n            # minimize the sum of squared deviations\n            distances = {}\n            for pair in self.symbol_pairs:\n                if self.history_price[pair[0]].IsReady and self.history_price[pair[1]].IsReady:\n                    if (self.Time.date() - self.Securities[pair[0]].GetLastData().Time.date()).days <= 3 and (self.Time.date() - self.Securities[pair[1]].GetLastData().Time.date()).days <= 3:\n                        distances[pair] = self.Distance([x for x in self.history_price[pair[0]]], [x for x in self.history_price[pair[1]]])\n            \n            if len(distances) != 0:\n                self.sorted_pairs = sorted(distances.items(), key = lambda x: x[1])[:self.max_traded_pairs]\n                self.sorted_pairs = [x[0] for x in self.sorted_pairs]\n            \n            self.Liquidate()\n            self.traded_pairs.clear()\n            self.traded_quantity.clear()\n            \n            self.days = 0\n        \n        self.days += 1\n        \n        if self.sorted_pairs is None: return\n    \n        pairs_to_remove = []\n    \n        for pair in self.sorted_pairs:\n            # Calculate the spread of two price series.\n            price_a = [x for x in self.history_price[pair[0]]]\n            price_b = [x for x in self.history_price[pair[1]]]\n            norm_a = np.array(price_a) / price_a[-1]\n            norm_b = np.array(price_b) / price_b[-1]\n            \n            spread = norm_a - norm_b\n            mean = np.mean(spread)\n            std = np.std(spread)\n            actual_spread = spread[0]\n            \n            # Long-short position is opened when pair prices have diverged by two standard deviations.\n            traded_portfolio_value = self.Portfolio.TotalPortfolioValue / self.max_traded_pairs\n            if actual_spread > mean + 0.5*std or actual_spread < mean - 0.5*std:\n                if pair not in self.traded_pairs:\n                    # open new position for pair, if there's place for it.\n                    if len(self.traded_pairs) < self.max_traded_pairs:\n                        symbol_a = pair[0]\n                        symbol_b = pair[1]\n                        a_price_norm = norm_a[0]\n                        b_price_norm = norm_b[0]\n                        a_price = price_a[0]\n                        b_price = price_b[0]\n                            \n                        # a etf's price > b etf's price\n                        if a_price_norm > b_price_norm:\n                            long_q = traded_portfolio_value / b_price    # long b etf\n                            short_q = -traded_portfolio_value / a_price  # short a etf\n                            if self.Securities.ContainsKey(symbol_a) and self.Securities.ContainsKey(symbol_b) and \\\n                                self.Securities[symbol_a].Price != 0 and self.Securities[symbol_a].IsTradable and \\\n                                self.Securities[symbol_b].Price != 0 and self.Securities[symbol_b].IsTradable:\n                                self.MarketOrder(symbol_a, short_q)\n                                self.MarketOrder(symbol_b, long_q)\n                                \n                                self.traded_quantity[pair] = (short_q, long_q)\n                                self.traded_pairs.append(pair)\n                        # b etf's price > a etf's price\n                        else:\n                            long_q = traded_portfolio_value / a_price    # long a etf\n                            short_q = -traded_portfolio_value / b_price  # short b etf\n                            if self.Securities.ContainsKey(symbol_a) and self.Securities.ContainsKey(symbol_b) and \\\n                                self.Securities[symbol_a].Price != 0 and self.Securities[symbol_a].IsTradable and \\\n                                self.Securities[symbol_b].Price != 0 and self.Securities[symbol_b].IsTradable:\n                                self.MarketOrder(symbol_a, long_q)\n                                self.MarketOrder(symbol_b, short_q)\n                                \n                                self.traded_quantity[pair] = (long_q, short_q)\n                                self.traded_pairs.append(pair)\n            # The position is closed when prices revert back.\n            else:\n                if pair in self.traded_pairs and pair in self.traded_quantity:\n                    # make opposite order to opened position\n                    self.MarketOrder(pair[0], -self.traded_quantity[pair][0])\n                    self.MarketOrder(pair[1], -self.traded_quantity[pair][1])\n                    pairs_to_remove.append(pair)\n            \n        for pair in pairs_to_remove:\n            self.traded_pairs.remove(pair)\n            del self.traded_quantity[pair]\n\n    def Distance(self, price_a, price_b):\n        # Calculate the sum of squared deviations between two normalized price series.\n        norm_a = np.array(price_a) / price_a[-1]\n        norm_b = np.array(price_b) / price_b[-1]\n        return sum((norm_a - norm_b)**2)\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/pairs-trading-with-stocks",
    "content": "#region imports\nfrom AlgorithmImports import *\n#endregion\n# https://quantpedia.com/strategies/pairs-trading-with-stocks/\n#\n# The investment universe consists of stocks from NYSE, AMEX, and NASDAQ, while illiquid stocks are removed from the investment universe. Cumulative\n# total return index is then created for each stock (dividends included), and the starting price during the formation period is set to $1 (price normalization). \n# Pairs are formed over twelve months (formation period) and are then traded in the next six-month period (trading period). The matching partner for each stock\n# is found by looking for the security that minimizes the sum of squared deviations between two normalized price series. Top 20 pairs with the smallest historical \n# distance measure are then traded, and a long-short position is opened when pair prices have diverged by two standard deviations, and the position is closed\n# when prices revert.\n#\n# QC implementation changes:\n#   - Universe consists of top 500 most liquid US stocks with price > 5$.\n#   - Maximum number of pairs traded at one time is set to 5.\n\nimport numpy as np\nimport itertools as it\n\nclass PairsTradingwithStocks(QCAlgorithm):\n    \n    def Initialize(self):\n        self.SetStartDate(2005, 1, 1)\n        self.SetCash(100000)\n       \n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n\n        # Daily price data.\n        self.history_price = {}\n        self.period = 12 * 21\n        \n        # Equally weighted brackets.\n        self.max_traded_pairs = 5\n        self.traded_pairs = []\n        self.traded_quantity = {}\n        \n        self.sorted_pairs = []\n        \n        self.coarse_count = 500\n        self.month = 6\n        self.selection_flag = True\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction)\n        self.Schedule.On(self.DateRules.MonthStart(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Selection)\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(5)\n            \n        for security in changes.RemovedSecurities:\n            symbol = security.Symbol\n            if symbol in self.history_price:\n                del self.history_price[symbol]\n            \n        symbols = [x for x in self.history_price.keys() if x != self.symbol]\n        self.symbol_pairs = list(it.combinations(symbols, 2))\n        \n        # minimize the sum of squared deviations\n        distances = {}\n        for pair in self.symbol_pairs:\n            if self.history_price[pair[0]].IsReady and self.history_price[pair[1]].IsReady:\n                distances[pair] = self.Distance(self.history_price[pair[0]], self.history_price[pair[1]])\n        \n        if len(distances) != 0:\n            self.sorted_pairs = [x[0] for x in sorted(distances.items(), key = lambda x: x[1])[:20]]\n        \n        self.Liquidate()\n        self.traded_pairs.clear()\n        self.traded_quantity.clear()\n\n    def CoarseSelectionFunction(self, coarse):\n        # Update the rolling window every day.\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            if symbol in self.history_price:\n                self.history_price[symbol].Add(stock.AdjustedPrice)\n\n        if not self.selection_flag:\n            return Universe.Unchanged\n        self.selection_flag = False\n        \n        selected = sorted([x for x in coarse if x.HasFundamentalData and x.Price > 5 and x.Market == 'usa'],\n            key=lambda x: x.DollarVolume, reverse=True)[:self.coarse_count]\n        \n        # Warmup price rolling windows.\n        for stock in selected:\n            symbol = stock.Symbol\n            \n            if symbol in self.history_price:\n                continue\n            \n            self.history_price[symbol] = RollingWindow[float](self.period)\n            history = self.History(symbol, self.period, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet\")\n                continue\n            closes = history.loc[symbol].close\n            for time, close in closes.iteritems():\n                self.history_price[symbol].Add(close)\n                \n        return [x.Symbol for x in selected if self.history_price[x.Symbol].IsReady]\n    \n    def OnData(self, data):\n        if self.sorted_pairs is None: return\n        \n        pairs_to_remove = []\n        \n        for pair in self.sorted_pairs:\n            # Calculate the spread of two price series.\n            price_a = [x for x in self.history_price[pair[0]]]\n            price_b = [x for x in self.history_price[pair[1]]]\n            norm_a = np.array(price_a) / price_a[-1]\n            norm_b = np.array(price_b) / price_b[-1]\n            \n            spread = norm_a - norm_b\n            mean = np.mean(spread)\n            std = np.std(spread)\n            actual_spread = spread[0]\n            \n            # Long-short position is opened when pair prices have diverged by two standard deviations.\n            traded_portfolio_value = self.Portfolio.TotalPortfolioValue / self.max_traded_pairs\n            if actual_spread > mean + 2*std or actual_spread < mean - 2*std:\n                if pair not in self.traded_pairs:\n                    # open new position for pair, if there's place for it.\n                    if len(self.traded_pairs) < self.max_traded_pairs:\n                        symbol_a = pair[0]\n                        symbol_b = pair[1]\n                        a_price_norm = norm_a[0]\n                        b_price_norm = norm_b[0]\n                        a_price = price_a[0]\n                        b_price = price_b[0]\n                        \n                        # a stock's price > b stock's price\n                        if a_price_norm > b_price_norm:\n                            long_q = traded_portfolio_value / b_price    # long b stock\n                            short_q = -traded_portfolio_value / a_price  # short a stock\n                            if self.Securities.ContainsKey(symbol_a) and self.Securities.ContainsKey(symbol_b) and \\\n                                self.Securities[symbol_a].Price != 0 and self.Securities[symbol_a].IsTradable and \\\n                                self.Securities[symbol_b].Price != 0 and self.Securities[symbol_b].IsTradable:\n                                self.MarketOrder(symbol_a, short_q)\n                                self.MarketOrder(symbol_b, long_q)\n                                \n                                self.traded_quantity[pair] = (short_q, long_q)\n                                self.traded_pairs.append(pair)\n                        # b stock's price > a stock's price\n                        else:\n                            long_q = traded_portfolio_value / a_price\n                            short_q = -traded_portfolio_value / b_price\n                            if self.Securities.ContainsKey(symbol_a) and self.Securities.ContainsKey(symbol_b) and \\\n                                self.Securities[symbol_a].Price != 0 and self.Securities[symbol_a].IsTradable and \\\n                                self.Securities[symbol_b].Price != 0 and self.Securities[symbol_b].IsTradable:\n                                self.MarketOrder(symbol_a, long_q)\n                                self.MarketOrder(symbol_b, short_q)\n\n                                self.traded_quantity[pair] = (long_q, short_q)\n                                self.traded_pairs.append(pair)\n            # The position is closed when prices revert back.\n            else:\n                if pair in self.traded_pairs and pair in self.traded_quantity:\n                    # make opposite order to opened position\n                    self.MarketOrder(pair[0], -self.traded_quantity[pair][0])\n                    self.MarketOrder(pair[1], -self.traded_quantity[pair][1])\n                    pairs_to_remove.append(pair)\n            \n        for pair in pairs_to_remove:\n            self.traded_pairs.remove(pair)\n            del self.traded_quantity[pair]\n            \n    def Distance(self, price_a, price_b):\n        # Calculate the sum of squared deviations between two normalized price series.\n        price_a = [x for x in price_a]\n        price_b = [x for x in price_b]\n        \n        norm_a = np.array(price_a) / price_a[-1]\n        norm_b = np.array(price_b) / price_b[-1]\n        return sum((norm_a - norm_b)**2)\n        \n    def Selection(self):\n        if self.month == 6:\n            self.selection_flag = True\n            \n        self.month += 1\n        if self.month > 12:\n            self.month = 1\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/payday-anomaly.py",
    "content": "# https://quantpedia.com/strategies/payday-anomaly/\n#\n# The investment universe consists of the S&P500 index. Simply, buy and hold the index during the 16th day in the month during each month of the year.\n\nfrom dateutil.relativedelta import relativedelta\nfrom AlgorithmImports import *\n\nclass PayDayAnomaly(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n        \n        self.symbol = self.AddEquity('SPY', Resolution.Minute).Symbol\n        self.liquidate_next_day = False\n        \n        self.Schedule.On(self.DateRules.EveryDay(self.symbol), self.TimeRules.BeforeMarketClose(self.symbol, 1), self.Purchase)\n    \n    def Purchase(self):\n        alg_time = self.Time\n        paydate = self.PaydayDate(alg_time)\n\n        if alg_time.date() == paydate:\n            self.SetHoldings(self.symbol, 1)\n            self.liquidate_next_day = True\n            # self.algorithm.EmitInsights(Insight.Price(self.symbol, timedelta(days=1), InsightDirection.Up, None, None, None, self.weight))\n\n        if self.liquidate_next_day:\n            self.liquidate_next_day = False\n            return\n        \n        if self.Portfolio[self.symbol].IsLong:\n            self.Liquidate(self.symbol)\n\n    def PaydayDate(self, date_time):\n        payday = date(date_time.year, date_time.month, 1) + relativedelta(day=15)\n        \n        if payday.weekday() == 5: # Is saturday.\n            payday = payday - timedelta(days=1)\n        elif payday.weekday() == 6: # Is sunday.\n            payday = payday - timedelta(days=2)\n        \n        return payday"
  },
  {
    "path": "static/strategies/rd-expenditures-and-stock-returns.py",
    "content": "# https://quantpedia.com/strategies/rd-expenditures-and-stock-returns/\n#\n# The investment universe consists of stocks that are listed on NYSE NASDAQ or AMEX. At the end of April, for each stock in the universe, calculate a measure of total R&D expenditures in the past 5 years scaled by the firm’s Market cap (defined on page 7, eq. 1).\n# Go long (short) on the quintile of firms with the highest (lowest) R&D expenditures relative to their Market Cap. Weight the portfolio equally and rebalance next year. The backtested performance of the paper is substituted by our more recent backtest in Quantconnect.\n\n# region imports\nfrom AlgorithmImports import *\nfrom numpy import log, average\nfrom scipy import stats\nimport numpy as np\n\n# endregion\n\n\nclass RDExpendituresandStockReturns(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(1998, 1, 1)\n        self.SetCash(100000)\n\n        self.weight = {}\n        self.coarse_count = 3000\n\n        # R&D history.\n        self.RD = {}\n        self.rd_period = 5\n\n        self.long = []\n        self.short = []\n\n        data = self.AddEquity(\"XLK\", Resolution.Daily)\n        data.SetLeverage(10)\n        self.technology_sector = data.Symbol\n\n        self.symbol = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n\n        self.selection_flag = True\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(\n            self.DateRules.MonthEnd(self.symbol),\n            self.TimeRules.AfterMarketOpen(self.symbol),\n            self.Selection,\n        )\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetLeverage(10)\n            security.SetFeeModel(CustomFeeModel())\n\n    def CoarseSelectionFunction(self, coarse):\n        if not self.selection_flag:\n            return Universe.Unchanged\n\n        selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Price > 5]\n\n        return selected\n\n    def FineSelectionFunction(self, fine):\n        fine = [\n            x\n            for x in fine\n            if (\n                x.FinancialStatements.IncomeStatement.ResearchAndDevelopment.TwelveMonths\n            )\n            and (x.MarketCap != 0)\n            and (\n                (x.SecurityReference.ExchangeId == \"NYS\")\n                or (x.SecurityReference.ExchangeId == \"NAS\")\n                or (x.SecurityReference.ExchangeId == \"ASE\")\n            )\n        ]\n        # and x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.Technology]\n\n        top_by_market_cap = None\n        if len(fine) > self.coarse_count:\n            sorted_by_market_cap = sorted(fine, key=lambda x: x.MarketCap, reverse=True)\n            top_by_market_cap = sorted_by_market_cap[: self.coarse_count]\n        else:\n            top_by_market_cap = fine\n\n        fine_symbols = [x.Symbol for x in top_by_market_cap]\n        ability = {}\n\n        updated_flag = []  # updated this year already\n\n        for stock in top_by_market_cap:\n            symbol = stock.Symbol\n\n            # prevent storing duplicated value for the same stock in one year\n            if symbol not in updated_flag:\n\n                # Update RD.\n                if symbol not in self.RD:\n                    self.RD[symbol] = RollingWindow[float](self.rd_period)\n                # rd = stock.FinancialStatements.IncomeStatement.ResearchAndDevelopment.TwelveMonths\n                # self.RD[symbol].Add(rd)\n\n                if self.RD[symbol].IsReady:\n                    coefs = np.array([1, 0.8, 0.6, 0.4, 0.2])\n                    rds = np.array([x for x in self.RD[symbol]])\n\n                    rdc = sum(coefs * rds)\n                    ability[stock] = rdc / stock.MarketCap\n\n                rd = (\n                    stock.FinancialStatements.IncomeStatement.ResearchAndDevelopment.TwelveMonths\n                )\n                self.RD[symbol].Add(rd)\n\n            # prevent storing duplicated value for the same stock in one year\n            if fine_symbols.count(symbol) > 1:\n                updated_flag.append(symbol)\n\n        # Ability market cap weighting.\n        # total_market_cap = sum([x.MarketCap for x in ability])\n        # for stock, rdc in ability.items():\n        # ability[stock] = rdc * (stock.MarketCap / total_market_cap)\n\n        # Remove not updated symbols\n        symbols_to_delete = []\n        for symbol in self.RD.keys():\n            if symbol not in fine_symbols:\n                symbols_to_delete.append(symbol)\n        for symbol in symbols_to_delete:\n            if symbol in self.RD:\n                del self.RD[symbol]\n\n        # starts trading after data storing period\n        if len(ability) != 0:\n            # Ability sorting.\n            sorted_by_ability = sorted(\n                ability.items(), key=lambda x: x[1], reverse=True\n            )\n            decile = int(len(sorted_by_ability) / 5)\n            high_by_ability = [x[0].Symbol for x in sorted_by_ability[:decile]]\n            low_by_ability = [x[0].Symbol for x in sorted_by_ability[-decile:]]\n\n            self.long = high_by_ability\n            self.short = low_by_ability\n            # self.short = [self.technology_sector]\n\n        return self.long + self.short\n\n    def Selection(self):\n        if self.Time.month == 4:\n            self.selection_flag = True\n\n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n\n        # Trade execution.\n        long_count = len(self.long)\n        short_count = len(self.short)\n\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.long + self.short:\n                self.Liquidate(symbol)\n\n        for symbol in self.long:\n            if (\n                self.Securities[symbol].Price != 0\n                and self.Securities[symbol].IsTradable\n            ):\n                self.SetHoldings(symbol, 1 / long_count)\n\n        for symbol in self.short:\n            if (\n                self.Securities[symbol].Price != 0\n                and self.Securities[symbol].IsTradable\n            ):\n                self.SetHoldings(symbol, -1 / short_count)\n\n        self.long.clear()\n        self.short.clear()\n\n\nclass SymbolData:\n    def __init__(self, tested_growth, period):\n        self.TestedGrowth = tested_growth\n        self.RD = RollingWindow[float](period)\n\n    def update(self, window_value):\n        self.RD.Add(window_value)\n\n    def is_ready(self):\n        return self.RD.IsReady\n\n\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n"
  },
  {
    "path": "static/strategies/rebalancing-premium-in-cryptocurrencies.py",
    "content": "# https://quantpedia.com/strategies/rebalancing-premium-in-cryptocurrencies/\n#\n# The investment universe consists of 27 cryptocurrencies: BAT (Basic Attention Token), BTC (Bitcoin), BTG (Bitcoin Gold),\n# DAI (Dai), DATA (Data Coin), DGB (DigiByte), EOS (EIS.io), ETH (Ethereum), FUN (FUN Token), IOTA (Iota), LRC (Loopring token),\n# LTC (Litecoin), MANA (Mana coin), NEO (Neo), OMG (OMG, Formally known as OmiseGo), REQ (Request), SAN (Santiment Network Token),\n# SNT (Status), TRX (Tron), WAX (Wax), XLM (Stellar), XMR (Monero), XRP (Ripple), XVG (Verge), ZEC (Zcash), ZIL (Zilliqa) and ZRX (0x).\n# Two portfolios are created. The first portfolio is the daily rebalanced portfolio of all 27 cryptos to ensure that the assets have equal weights.\n# The second portfolio is not rebalanced at all: an investor buys the equally-weighted crypto portfolio and lets the weights drift.\n# Then the investor goes long the first portfolio and shorts the second portfolio with 70% weight.\n#\n# QC Implementation:\n#   - BTGUSD is not traded due to data error.\n\nfrom AlgorithmImports import *\n\nclass RebalancingPremiumInCryptocurrencies(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2015, 1, 1)\n        self.SetCash(100000000)\n        \n        self.cryptos = [\n            \"BTCUSD\", \n            \"BATUSD\", \n            # \"BTGUSD\", \n            \"DAIUSD\",\n            \"DGBUSD\", \"EOSUSD\",\n            \"ETHUSD\", \"FUNUSD\",\n            \"LTCUSD\", \"NEOUSD\",\n            \"OMGUSD\", \"SNTUSD\",\n            \"TRXUSD\", \"XLMUSD\",\n            \"XMRUSD\", \"XRPUSD\",\n            \"XVGUSD\", \"ZECUSD\",\n            \"ZRXUSD\", \"LRCUSD\",\n            \"REQUSD\", \"SANUSD\",\n            \"WAXUSD\", \"ZILUSD\",\n            \"IOTAUSD\", \n            \"MANAUSD\",\n            \"DATAUSD\"\n        ]\n\n        self.short_side_percentage = 0.7\n        self.data = {}\n        self.SetBrokerageModel(BrokerageName.Bitfinex)\n        \n        for crypto in self.cryptos:\n            # GDAX is coinmarket, but it doesn't support this many cryptos, so we choose Bitfinex\n            data = self.AddCrypto(crypto, Resolution.Minute, Market.Bitfinex)\n            data.SetFeeModel(CustomFeeModel())\n            data.SetLeverage(10)\n            \n            self.data[crypto] = SymbolData()\n\n        self.was_traded_already = False         # wait for the price data to come only once\n        self.prev_short_portfolio_equity = 0    # short leg equity tracking\n\n    def OnData(self, data):\n        if not (self.Time.hour == 9 and self.Time.minute == 30):\n            return\n        \n        all_cryptos_are_ready = True       # data warmup flag\n\n        # check if all cryptos has ready data\n        for crypto in self.cryptos:\n            if crypto in data and data[crypto]:\n                # update crypto price for weight calculation\n                self.data[crypto].last_price = data[crypto].Value\n            # if there is at least one crypto, which doesn't have data, then don't trade and break cycle\n            else:\n                all_cryptos_are_ready = False\n                break\n        \n        if all_cryptos_are_ready or self.was_traded_already:\n            self.was_traded_already = True\n            \n            # long strategy equity calculation\n            long_portfolio_equity = self.Portfolio.TotalPortfolioValue\n            long_equity_to_trade = long_portfolio_equity / len(self.cryptos)\n            \n            # short strategy equity calculation\n            short_portfolio_equity = self.Portfolio.TotalPortfolioValue * self.short_side_percentage\n            short_equity_to_trade = short_portfolio_equity / len(self.cryptos)\n\n            # trading/rebalance\n            for crypto, symbol_obj in self.data.items():\n                if crypto in data and data[crypto]:\n                    # short strategy\n                    if not self.Portfolio[crypto].Invested:\n                        short_q = np.floor(short_equity_to_trade / symbol_obj.last_price)\n                        if abs(short_q) >= self.Securities[crypto].SymbolProperties.MinimumOrderSize:\n                            self.MarketOrder(crypto, -short_q)\n\n                    # long strategy\n                    long_q = np.floor(long_equity_to_trade / symbol_obj.last_price)\n                    # currency was traded before\n                    if symbol_obj.quantity is not None:\n                        # calculate quantity difference\n                        diff_q = long_q - symbol_obj.quantity\n                    \n                        # rebalance position\n                        if abs(diff_q) >= self.Securities[crypto].SymbolProperties.MinimumOrderSize:\n                            self.MarketOrder(crypto, diff_q)\n                            \n                            # change new quantity\n                            symbol_obj.quantity += diff_q\n                    else:\n                        # rebalance position\n                        if abs(long_q) >= self.Securities[crypto].SymbolProperties.MinimumOrderSize:\n                            self.MarketOrder(crypto, long_q)\n                        \n                            # change new quantity\n                            symbol_obj.quantity = long_q\n    \nclass SymbolData():\n    def __init__(self):\n        self.last_price = None\n        self.quantity = None\n    \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/residual-momentum-factor.py",
    "content": "# https://quantpedia.com/strategies/residual-momentum-factor/\n#\n# The investment universe consists of all domestic, primary stocks listed on the New York (NYSE), American (AMEX), and NASDAQ \n# stock markets with a price higher than $1. Closed-end funds, REITs, unit trusts, ADRs, and foreign stocks are removed. The \n# 10% largest stocks in terms of market capitalization are then selected for trading.\n# The residual momentum strategy is defined as a zero-investment top-minus-bottom decile portfolio based on ranking stocks \n# every month on their past 12-month residual returns, excluding the most recent month, standardized by the standard deviation\n# of the residual returns over the same period. Residual returns are estimated each month for all stocks over the past 36 months\n# using a regression model. The regression model is calculated every month for all eligible stocks using the Fama and French \n# three factors as independent variables. The portfolio is equally weighted and rebalanced monthly.\n#\n# QC implementation changes:\n#   - Universe consists of top 3000 US stock by market cap from NYSE, AMEX and NASDAQ.\n\nimport numpy as np\nfrom AlgorithmImports import *\nimport statsmodels.api as sm\n\nclass ResidualMomentumFactor(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.coarse_count = 500\n\n        # Monthly price data.\n        self.data = {}\n        self.period = 37\n\n        # Warmup market monthly data.\n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        self.data[self.symbol] = RollingWindow[float](self.period)\n        \n        history = self.History(self.symbol, self.period * 21, Resolution.Daily)\n        if history.empty:\n            self.Log(f\"Not enough data for {self.symbol} yet.\")\n        else:    \n            closes = history.loc[self.symbol].close\n            closes_len = len(closes.keys())\n            # Find monthly closes.\n            for index, time_close in enumerate(closes.iteritems()):\n                # index out of bounds check.\n                if index + 1 < closes_len:\n                    date_month = time_close[0].date().month\n                    next_date_month = closes.keys()[index + 1].month\n                \n                    # Found last day of month.\n                    if date_month != next_date_month:\n                        self.data[self.symbol].Add(time_close[1])        \n        \n        # Factors.\n        self.size_factor_symbols = []                                   # Symbol,long_flag tuple.\n        self.size_factor_vector = RollingWindow[float](self.period - 1) # Monthly performance.\n\n        self.value_factor_symbols = []\n        self.value_factor_vector = RollingWindow[float](self.period - 1)\n        \n        # Monthly residual returns for each stock.\n        self.residual_return = {}\n        self.residual_momentum_period = 12\n        \n        self.long = []\n        self.short = []\n        \n        self.last_month = -1\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        \n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetLeverage(10)\n            security.SetFeeModel(CustomFeeModel())\n    \n    def CoarseSelectionFunction(self, coarse):\n        if not self.selection_flag:\n            return Universe.Unchanged\n\n        # Update the rolling window every month.\n        for stock in coarse:\n            symbol = stock.Symbol\n            \n            # Store monthly market price.\n            if symbol == self.symbol:\n                self.data[self.symbol].Add(stock.AdjustedPrice)\n            else:\n                # Store monthly stock price.\n                if symbol in self.data:\n                    self.data[symbol].Add(stock.AdjustedPrice)\n\n        selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa']\n        # selected = [x.Symbol\n        #     for x in sorted([x for x in coarse if x.HasFundamentalData and x.Market == 'usa'],\n        #         key = lambda x: x.DollarVolume, reverse = True)[:self.coarse_count]]\n        \n        # Warmup price rolling windows.\n        for symbol in selected:\n            if symbol in self.data:\n                continue\n            \n            self.data[symbol] = RollingWindow[float](self.period)\n            history = self.History(symbol, self.period * 21, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet.\")\n                continue\n            closes = history.loc[symbol].close\n            \n            closes_len = len(closes.keys())\n            # Find monthly closes.\n            for index, time_close in enumerate(closes.iteritems()):\n                # index out of bounds check.\n                if index + 1 < closes_len:\n                    date_month = time_close[0].date().month\n                    next_date_month = closes.keys()[index + 1].month\n                \n                    # Found last day of month.\n                    if date_month != next_date_month:\n                        self.data[symbol].Add(time_close[1])\n            \n        return [x for x in selected if self.data[x].IsReady]        \n\n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0 and x.CompanyReference.IsREIT == 0 and      \\\n                ((x.SecurityReference.ExchangeId == \"NYS\") or (x.SecurityReference.ExchangeId == \"NAS\") or (x.SecurityReference.ExchangeId == \"ASE\"))]\n                \n        if len(fine) > self.coarse_count:\n            sorted_by_market_cap = sorted(fine, key = lambda x: x.MarketCap, reverse=True)\n            top_by_market_cap = sorted_by_market_cap[:self.coarse_count]\n        else:\n            top_by_market_cap = fine\n\n        # Size factor.\n        # sorted_by_market_cap = sorted(top_by_market_cap, key = lambda x:(x.MarketCap), reverse=False)\n        quintile = int(len(top_by_market_cap) / 5)\n        size_factor_long = [ (i.Symbol,True) for i in top_by_market_cap[-quintile:]]\n        size_factor_short = [(i.Symbol,False) for i in top_by_market_cap[:quintile]]\n        # Calculate last month's performance.\n        if len(self.size_factor_symbols) != 0:\n            monthly_return = self.CalculateFactorPerformance(self.data, self.size_factor_symbols)\n            if monthly_return != 0:\n                self.size_factor_vector.Add(monthly_return)\n        # Store new factor symbols.\n        self.size_factor_symbols = size_factor_long + size_factor_short\n                \n        # Value factor.\n        sorted_by_pb = sorted(top_by_market_cap, key = lambda x:(x.ValuationRatios.PBRatio), reverse=False)\n        quintile = int(len(sorted_by_pb) / 5)\n        value_factor_long = [(i.Symbol,True) for i in sorted_by_pb[:quintile]]\n        value_factor_short = [(i.Symbol,False) for i in sorted_by_pb[-quintile:]]\n        # Calculate last month's performance.\n        if len(self.value_factor_symbols) != 0:\n            monthly_return = self.CalculateFactorPerformance(self.data, self.value_factor_symbols)\n            if monthly_return != 0:\n                self.value_factor_vector.Add(monthly_return)\n        # Store new factor symbols.\n        self.value_factor_symbols = value_factor_long + value_factor_short\n            \n        # Every factor vector is ready.\n        if self.size_factor_vector.IsReady and self.value_factor_vector.IsReady:\n            \n            # Market factor.\n            market_factor = []\n            if self.symbol in self.data and self.data[self.symbol].IsReady:\n                market_factor_prices = np.array([x for x in self.data[self.symbol]])\n                market_factor = (market_factor_prices[:-1] - market_factor_prices[1:]) / market_factor_prices[1:]\n            \n                if len(market_factor) == (self.period - 1): \n                    # Residual return calc.\n                    x = [\n                        [x for x in market_factor], \n                        [x for x in self.size_factor_vector], \n                        [x for x in self.value_factor_vector]\n                    ]\n                    \n                    standardized_residual_momentum = {}\n                    for stock in top_by_market_cap:\n                        symbol = stock.Symbol\n                        if symbol in self.data and self.data[symbol].IsReady:\n                            monthly_prices = np.array([x for x in self.data[symbol]])\n                            monthly_returns = (monthly_prices[:-1] - monthly_prices[1:]) / monthly_prices[1:]\n                            \n                            regression_model = self.MultipleLinearRegression(x, monthly_returns)\n                            alpha = regression_model.params[0]\n                            \n                            if symbol not in self.residual_return:\n                                self.residual_return[symbol] = RollingWindow[float](self.residual_momentum_period)\n                            self.residual_return[symbol].Add(alpha)\n                            \n                            # Residual data for 12 months is ready.\n                            if self.residual_return[symbol].IsReady:\n                                residual_returns = [x for x in self.residual_return[symbol]]\n                                standardized_residual_momentum[symbol] = sum(residual_returns) / np.std(residual_returns)\n        \n                    sorted_by_resid_momentum = sorted(standardized_residual_momentum.items(), key = lambda x: x[1], reverse=True)\n                    decile = int(len(sorted_by_resid_momentum) / 10)\n                    self.long = [x[0] for x in sorted_by_resid_momentum[:decile]]\n                    self.short = [x[0] for x in sorted_by_resid_momentum[-decile:]]\n \n        return self.long + self.short\n    \n    def OnData(self, data):\n        if self.Time.month != self.last_month:\n            self.last_month = self.Time.month\n            self.selection_flag = True\n            return\n        \n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n        \n        # Trade execution.\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.long + self.short:\n                self.Liquidate(symbol)\n\n        for symbol in self.long:\n            self.SetHoldings(symbol, 1 / len(self.long))\n        for symbol in self.short:\n            self.SetHoldings(symbol, -1 / len(self.short))\n        \n        self.long.clear()\n        self.short.clear()\n\n    def CalculateFactorPerformance(self, data, factor_symbols):\n        monthly_return = 0\n        if len(factor_symbols) != 0:\n            for symbol, long_flag in factor_symbols:\n                if symbol in data and data[symbol].Count >= 2:\n                    closes = [x for x in data[symbol]]\n                    if long_flag:\n                        monthly_return += ((closes[0] / closes[1] - 1) / len(factor_symbols))\n                    else:\n                        monthly_return -= ((closes[0] / closes[1] - 1) / len(factor_symbols))\n\n        return monthly_return\n\n    def MultipleLinearRegression(self, x, y):\n        x = np.array(x).T\n        x = sm.add_constant(x)\n        result = sm.OLS(endog=y, exog=x).fit()\n        return result\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/return-asymmetry-effect-in-commodity-futures.py",
    "content": "# https://quantpedia.com/strategies/return-asymmetry-effect-in-commodity-futures/\n#\n# The investment universe consists of 22 commodity futures, namely:\n# soybean oil, corn, cocoa, cotton, feeder cattle, gold, copper, heating oil, coffee, live cattle, lean hogs,\n# natural gas, oats, orange juice, palladium, platinum, soybean, sugar, silver, soybean meal, wheat, and crude oil.\n# Firstly, at the beginning of each month, construct the asymmetry measure (IE) for each commodity based on the latest 260 daily returns using the following formula\n# (the formula originally consists of theoretical density and integrals, however the solution is simple when empirical distribution is utilized):\n# IE = (number of trading days when the daily return is greater than the average plus two standard deviations) – \n# (number of trading days when the daily return is smaller than the average minus two standard deviations).\n# Then rank the commodities according to their IE.\n# Buy the bottom seven commodities with the lowest IE in the previous month and sell the top seven commodities with the highest IE in the previous month.\n# Weigh the portfolio equally and rebalance monthly.\n#\n# QC Implementation:\n#   - Universe consists of Quantpedia comodity futures.\n#   - Buying bottom 7 commodities and selling top 7 commodities according to IE.\n\nfrom AlgorithmImports import *\n\nclass ReturnAsymmetryEffectInCommodityFutures(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n        \n        self.tickers = [\n            \"CME_S1\",   # Soybean Futures, Continuous Contract\n            \"CME_W1\",   # Wheat Futures, Continuous Contract\n            \"CME_SM1\",  # Soybean Meal Futures, Continuous Contract\n            \"CME_BO1\",  # Soybean Oil Futures, Continuous Contract\n            \"CME_C1\",   # Corn Futures, Continuous Contract\n            \"CME_O1\",   # Oats Futures, Continuous Contract\n            \"CME_LC1\",  # Live Cattle Futures, Continuous Contract\n            \"CME_FC1\",  # Feeder Cattle Futures, Continuous Contract\n            \"CME_LN1\",  # Lean Hog Futures, Continuous Contract\n            \"CME_GC1\",  # Gold Futures, Continuous Contract\n            \"CME_SI1\",  # Silver Futures, Continuous Contract\n            \"CME_PL1\",  # Platinum Futures, Continuous Contract\n            \"CME_CL1\",  # Crude Oil Futures, Continuous Contract\n            \"CME_HG1\",  # Copper Futures, Continuous Contract\n            \"CME_LB1\",  # Random Length Lumber Futures, Continuous Contract\n            # \"CME_NG1\",  # Natural Gas (Henry Hub) Physical Futures, Continuous Contract\n            \"CME_PA1\",  # Palladium Futures, Continuous Contract \n            \"CME_RR1\",  # Rough Rice Futures, Continuous Contract\n            \"CME_RB2\",  # Gasoline Futures, Continuous Contract\n            \"CME_KW2\",  # Wheat Kansas, Continuous Contract\n            \n            \"ICE_CC1\",  # Cocoa Futures, Continuous Contract \n            \"ICE_CT1\",  # Cotton No. 2 Futures, Continuous Contract\n            \"ICE_KC1\",  # Coffee C Futures, Continuous Contract\n            \"ICE_O1\",   # Heating Oil Futures, Continuous Contract\n            \"ICE_OJ1\",  # Orange Juice Futures, Continuous Contract\n            \"ICE_SB1\"   # Sugar No. 11 Futures, Continuous Contract\n            \"ICE_RS1\",  # Canola Futures, Continuous Contract\n            \"ICE_GO1\",  # Gas Oil Futures, Continuous Contract\n            \"ICE_WT1\",  # WTI Crude Futures, Continuous Contract\n        ]\n        \n        self.data = {} # storing objects of SymbolData class keyed by comodity symbols\n        \n        self.period = 261 # need 261 daily prices, to calculate 260 daily returns\n        self.buy_count = 7 # buy n comodities on each rebalance\n        self.sell_count = 7 # sell n comodities on each rebalance\n        \n        self.symbol = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n        \n        # subscribe to futures contracts\n        for ticker in self.tickers:\n            security = self.AddData(QuantpediaFutures, ticker, Resolution.Daily)\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(5)\n            \n            self.data[security.Symbol] = SymbolData(self.period)\n        \n        self.rebalance_flag = False   \n        self.Schedule.On(self.DateRules.MonthStart(self.symbol), self.TimeRules.BeforeMarketClose(self.symbol, 0), self.Rebalance)\n\n    def OnData(self, data):\n        # update daily closes\n        for symbol in self.data:\n            if symbol in data and data[symbol]:\n                close = data[symbol].Value\n                self.data[symbol].update_closes(close)\n        \n        # rebalance monthly        \n        if not self.rebalance_flag:\n            return\n        self.rebalance_flag = False\n                \n        IE = {}\n        \n        for symbol, symbol_obj in self.data.items():\n            # check if comodity has ready prices\n            if not symbol_obj.is_ready():\n                continue\n            \n            # calculate IE\n            IE_value = symbol_obj.calculate_IE()\n            \n            # store IE value under comodity symbol\n            IE[symbol] = IE_value\n            \n        # make sure, there are enough comodities for rebalance\n        if len(IE) < (self.buy_count + self.sell_count):\n            return\n        \n        # sort commodities based on IE values\n        sorted_by_IE = [x[0] for x in sorted(IE.items(), key=lambda item: item[1])]\n        \n        # select long and short parts\n        long = sorted_by_IE[:self.buy_count]\n        short = sorted_by_IE[-self.sell_count:]\n        \n        # trade execution\n        invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in invested:\n            if symbol not in long + short:\n                self.Liquidate(symbol)\n                \n        for symbol in long:\n            self.SetHoldings(symbol, 1 / self.buy_count)\n            \n        for symbol in short:\n            self.SetHoldings(symbol, -1 / self.sell_count)\n                \n    def Rebalance(self):\n        self.rebalance_flag = True\n            \nclass SymbolData():\n    def __init__(self, period):\n        self.closes = RollingWindow[float](period)\n        \n    def update_closes(self, close):\n        self.closes.Add(close)\n        \n    def is_ready(self):\n        return self.closes.IsReady\n        \n    def calculate_IE(self):\n        closes = np.array([x for x in self.closes])\n        daily_returns = (closes[:-1] - closes[1:]) / closes[1:]\n        \n        average_daily_returns = np.average(daily_returns)\n        two_daily_returns_std = 2 * np.std(daily_returns)\n        \n        avg_plus_two_std = average_daily_returns + two_daily_returns_std\n        avg_minus_two_std = average_daily_returns - two_daily_returns_std\n        \n        over_avg_plus_two_std = 0 # counting number of daily returns, which were over avg_plus_two_std\n        under_avg_minus_two_std = 0 # counting number of daily returns, which were under avg_minus_two_std\n        \n        for daily_return in daily_returns:\n            if daily_return > avg_plus_two_std:\n                over_avg_plus_two_std += 1\n            elif daily_return < avg_minus_two_std:\n                under_avg_minus_two_std += 1\n                \n        IE_value = over_avg_plus_two_std - under_avg_minus_two_std\n        \n        return IE_value\n        \n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n        split = line.split(';')\n        \n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data['back_adjusted'] = float(split[1])\n        data['spliced'] = float(split[2])\n        data.Value = float(split[1])\n\n        return data\n        \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/reversal-during-earnings-announcements.py",
    "content": "from AlgorithmImports import *\n\nimport numpy as np\nimport statsmodels.api as sm\n\n# Custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n\n\n# NOTE: Manager for new trades. It's represented by certain count of equally weighted brackets for long and short positions.\n# If there's a place for new trade, it will be managed for time of holding period.\nclass TradeManager:\n    def __init__(self, algorithm, long_size, short_size, holding_period):\n        self.algorithm = algorithm  # algorithm to execute orders in.\n\n        self.long_size = long_size\n        self.short_size = short_size\n\n        self.long_len = 0\n        self.short_len = 0\n\n        # Arrays of ManagedSymbols\n        self.symbols = []\n\n        self.holding_period = holding_period  # Days of holding.\n\n    # Add stock symbol object\n    def Add(self, symbol, long_flag):\n        # Open new long trade.\n        managed_symbol = ManagedSymbol(symbol, self.holding_period, long_flag)\n\n        if long_flag:\n            # If there's a place for it.\n            if self.long_len < self.long_size:\n                self.symbols.append(managed_symbol)\n                self.algorithm.SetHoldings(symbol, 1 / self.long_size)\n                self.long_len += 1\n            else:\n                self.algorithm.Log(\"There's not place for additional trade.\")\n\n        # Open new short trade.\n        else:\n            # If there's a place for it.\n            if self.short_len < self.short_size:\n                self.symbols.append(managed_symbol)\n                self.algorithm.SetHoldings(symbol, -1 / self.short_size)\n                self.short_len += 1\n            else:\n                self.algorithm.Log(\"There's not place for additional trade.\")\n\n    # Decrement holding period and liquidate symbols.\n    def TryLiquidate(self):\n        symbols_to_delete = []\n        for managed_symbol in self.symbols:\n            managed_symbol.days_to_liquidate -= 1\n\n            # Liquidate.\n            if managed_symbol.days_to_liquidate == 0:\n                symbols_to_delete.append(managed_symbol)\n                self.algorithm.Liquidate(managed_symbol.symbol)\n\n                if managed_symbol.long_flag:\n                    self.long_len -= 1\n                else:\n                    self.short_len -= 1\n\n        # Remove symbols from management.\n        for managed_symbol in symbols_to_delete:\n            self.symbols.remove(managed_symbol)\n\n    def LiquidateTicker(self, ticker):\n        symbol_to_delete = None\n        for managed_symbol in self.symbols:\n            if managed_symbol.symbol.Value == ticker:\n                self.algorithm.Liquidate(managed_symbol.symbol)\n                symbol_to_delete = managed_symbol\n                if managed_symbol.long_flag:\n                    self.long_len -= 1\n                else:\n                    self.short_len -= 1\n\n                break\n\n        if symbol_to_delete:\n            self.symbols.remove(symbol_to_delete)\n        else:\n            self.algorithm.Debug(\"Ticker is not held in portfolio!\")\n\n\nclass ManagedSymbol:\n    def __init__(self, symbol, days_to_liquidate, long_flag):\n        self.symbol = symbol\n        self.days_to_liquidate = days_to_liquidate\n        self.long_flag = long_flag\n\n\n# https://quantpedia.com/strategies/reversal-during-earnings-announcements/\n#\n# The investment universe consists of stocks listed at NYSE, AMEX, and NASDAQ, whose daily price data are available at the CRSP database.\n# Earnings-announcement dates are collected from Compustat. Firstly, the investor sorts stocks into quintiles based on firm size. Then he\n# further sorts the stocks in the top quintile (the biggest) into quintiles based on their average returns in the 3-day window between\n# t-4 and t-2, where t is the day of the earnings announcement. The investor goes long on the bottom quintile (past losers) and short on\n# the top quintile (past winners) and holds the stocks during the 3-day window between t-1, t, and t+1. Stocks in the portfolios are\n# weighted equally.\n#\n# QC Impelmentation:\n#   - Universe consits of stocks, which have earnings dates in Quantpedia data.\n#   - Maximum of 20 long and 20 short stock are held at the same time.\n\nimport data_tools\nfrom AlgorithmImports import *\nimport numpy as np\nfrom collections import deque\n\n\nclass ReversalDuringEarningsAnnouncements(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2010, 1, 1)  # earnings dates start in 2010\n        self.SetCash(100000)\n\n        self.ear_period = 4\n        self.symbol = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n\n        # Daily price data.\n        self.data = {}\n\n        # Import earnigns data.\n        self.earnings_data = {}\n\n        # Available symbols from earning_dates.csv.\n        self.tickers: Set(str) = set()\n\n        self.first_date: datetime.date | None = None\n\n        earnings_data: str = self.Download(\n            \"data.quantpedia.com/backtesting_data/economic/earnings_dates_eps.json\"\n        )\n        earnings_data_json: list[dict] = json.loads(earnings_data)\n\n        for obj in earnings_data_json:\n            date: datetime.date = datetime.strptime(obj[\"date\"], \"%Y-%m-%d\").date()\n            self.earnings_data[date] = []\n\n            if not self.first_date:\n                self.first_date = date\n\n            for stock_data in obj[\"stocks\"]:\n                ticker: str = stock_data[\"ticker\"]\n\n                self.earnings_data[date].append(ticker)\n                self.tickers.add(ticker)\n\n        # EAR history for previous quarter used for statistics.\n        self.ear_previous_quarter = []\n        self.ear_actual_quarter = []\n\n        # 5 equally weighted brackets for traded symbols. - 20 symbols long , 20 for short, 3 days of holding.\n        self.trade_manager = data_tools.TradeManager(self, 20, 20, 3)\n\n        self.month: int = 0\n        self.selection_flag = False\n        self.rebalance_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction)\n        self.Schedule.On(\n            self.DateRules.MonthEnd(self.symbol),\n            self.TimeRules.AfterMarketOpen(self.symbol),\n            self.Selection,\n        )\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(data_tools.CustomFeeModel())\n            security.SetLeverage(5)\n\n    def CoarseSelectionFunction(self, coarse):\n        # update daily prices\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            if symbol in self.data:\n                self.data[symbol].Add(stock.AdjustedPrice)\n\n        if not self.selection_flag:\n            return Universe.Unchanged\n        self.selection_flag = False\n\n        selected = [x.Symbol for x in coarse if x.Symbol.Value in self.tickers]\n\n        for symbol in selected:\n            if symbol in self.data:\n                continue\n\n            self.data[symbol] = RollingWindow[float](self.ear_period)\n            history = self.History(symbol, self.ear_period, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet\")\n                continue\n\n            closes = history.loc[symbol].close\n            for time, close in closes.iteritems():\n                self.data[symbol].Add(close)\n\n        return selected\n\n    def OnData(self, data):\n        date_to_lookup = (self.Time + timedelta(days=1)).date()\n\n        # Liquidate opened symbols after three days.\n        self.trade_manager.TryLiquidate()\n\n        ret_t4_t2 = {}\n\n        for symbol in self.data:\n            # Data is ready.\n            if self.data[symbol].IsReady:\n                # Earnings is in next two day for the symbol.\n                if (\n                    date_to_lookup in self.earnings_data\n                    and symbol.Value in self.earnings_data[date_to_lookup]\n                ):\n                    closes = [x for x in self.data[symbol]]\n                    # Calculate t-4 to t-2 return.\n                    ret = (closes[0] - closes[-1]) / closes[-1]\n                    ret_t4_t2[symbol] = ret\n\n                    # Store return in this month's history.\n                    self.ear_actual_quarter.append(ret)\n\n        # Wait until we have history data for previous three months.\n        if len(self.ear_previous_quarter) != 0:\n            # Sort by EAR.\n            ear_values = self.ear_previous_quarter\n            top_ear_quintile = np.percentile(ear_values, 80)\n            bottom_ear_quintile = np.percentile(ear_values, 20)\n\n            # Store symbol to set.\n            long = [\n                x[0]\n                for x in ret_t4_t2.items()\n                if x[1] <= bottom_ear_quintile and x[0] in data and data[x[0]]\n            ]\n            short = [\n                x[0]\n                for x in ret_t4_t2.items()\n                if x[1] >= top_ear_quintile and x[0] in data and data[x[0]]\n            ]\n\n            # Open new trades.\n            for symbol in long:\n                self.trade_manager.Add(symbol, True)\n            for symbol in short:\n                self.trade_manager.Add(symbol, False)\n\n    def Selection(self):\n        # There is no earnings data yet.\n        if self.Time.date() < self.first_date:\n            return\n\n        self.selection_flag = True\n\n        # Every three months.\n        if self.month % 3 == 0:\n            # Save quarter history.\n            self.ear_previous_quarter = [x for x in self.ear_actual_quarter]\n            self.ear_actual_quarter.clear()\n\n        self.month += 1\n"
  },
  {
    "path": "static/strategies/roa-effect-within-stocks.py",
    "content": "# https://quantpedia.com/strategies/roa-effect-within-stocks/\n#\n# The investment universe contains all stocks on NYSE and AMEX and Nasdaq with Sales greater than 10 million USD. Stocks are then sorted into\n# two halves based on market capitalization. Each half is then divided into deciles based on Return on assets (ROA) calculated as quarterly\n# earnings (Compustat quarterly item IBQ – income before extraordinary items) divided by one-quarter-lagged assets (item ATQ – total assets).\n# The investor then goes long the top three deciles from each market capitalization group and goes short bottom three deciles. The strategy is\n# rebalanced monthly, and stocks are equally weighted.\n#\n# QC implementation changes:\n#   - Instead of all listed stock, we select 500 most liquid stocks traded on NYSE, AMEX, or NASDAQ.\n\nfrom AlgorithmImports import *\n\n\nclass ROAEffectWithinStocks(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.symbol = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n\n        self.course_count = 500\n\n        self.long = []\n        self.short = []\n\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(\n            self.DateRules.MonthEnd(self.symbol),\n            self.TimeRules.AfterMarketOpen(self.symbol),\n            self.Selection,\n        )\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(5)\n\n    def CoarseSelectionFunction(self, coarse):\n        if not self.selection_flag:\n            return Universe.Unchanged\n\n        selected = sorted(\n            [\n                x\n                for x in coarse\n                if x.HasFundamentalData and x.Market == \"usa\" and x.Price > 5\n            ],\n            key=lambda x: x.DollarVolume,\n            reverse=True,\n        )\n\n        return [x.Symbol for x in selected[: self.course_count]]\n\n    def FineSelectionFunction(self, fine):\n        fine = [\n            x\n            for x in fine\n            if x.MarketCap != 0\n            and x.ValuationRatios.SalesPerShare\n            * x.EarningReports.DilutedAverageShares.Value\n            > 10000000\n            and x.OperationRatios.ROA.ThreeMonths != 0\n            and (\n                (x.SecurityReference.ExchangeId == \"NYS\")\n                or (x.SecurityReference.ExchangeId == \"NAS\")\n                or (x.SecurityReference.ExchangeId == \"ASE\")\n            )\n        ]\n\n        # Sorting by market cap.\n        sorted_by_market_cap = sorted(fine, key=lambda x: x.MarketCap, reverse=True)\n        half = int(len(sorted_by_market_cap) / 2)\n        top_mc = [x for x in sorted_by_market_cap[:half]]\n        bottom_mc = [x for x in sorted_by_market_cap[half:]]\n\n        if len(top_mc) >= 10 and len(bottom_mc) >= 10:\n            # Sorting by ROA.\n            sorted_top_by_roa = sorted(\n                top_mc, key=lambda x: (x.OperationRatios.ROA.Value), reverse=True\n            )\n            decile = int(len(sorted_top_by_roa) / 10)\n            long_top = [x.Symbol for x in sorted_top_by_roa[: decile * 3]]\n            short_top = [x.Symbol for x in sorted_top_by_roa[-(decile * 3) :]]\n\n            sorted_bottom_by_roa = sorted(\n                bottom_mc, key=lambda x: (x.OperationRatios.ROA.Value), reverse=True\n            )\n            decile = int(len(sorted_bottom_by_roa) / 10)\n            long_bottom = [x.Symbol for x in sorted_bottom_by_roa[: decile * 3]]\n            short_bottom = [x.Symbol for x in sorted_bottom_by_roa[-(decile * 3) :]]\n\n            self.long = long_top + long_bottom\n            self.short = short_top + short_bottom\n\n        return self.long + self.short\n\n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n\n        # Trade execution.\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.long + self.short:\n                self.Liquidate(symbol)\n\n        long_count = len(self.long)\n        short_count = len(self.short)\n\n        for symbol in self.long:\n            self.SetHoldings(symbol, 1 / long_count)\n        for symbol in self.short:\n            self.SetHoldings(symbol, -1 / short_count)\n\n        self.long.clear()\n        self.short.clear()\n\n    def Selection(self):\n        self.selection_flag = True\n\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n"
  },
  {
    "path": "static/strategies/sector-momentum-rotational-system.py",
    "content": "# region imports\nfrom AlgorithmImports import *\n\n# endregion\n# https://quantpedia.com/strategies/sector-momentum-rotational-system/\n#\n# Use ten sector ETFs. Pick 3 ETFs with the strongest 12-month momentum into your portfolio and weight them equally. Hold them for one month and then rebalance.\n\n\nclass SectorMomentumAlgorithm(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        # Daily ROC data.\n        self.data = {}\n\n        self.period = 12 * 21\n        self.SetWarmUp(self.period)\n\n        self.symbols = [\n            \"VNQ\",  # Vanguard Real Estate Index Fund\n            \"XLK\",  # Technology Select Sector SPDR Fund\n            \"XLE\",  # Energy Select Sector SPDR Fund\n            \"XLV\",  # Health Care Select Sector SPDR Fund\n            \"XLF\",  # Financial Select Sector SPDR Fund\n            \"XLI\",  # Industrials Select Sector SPDR Fund\n            \"XLB\",  # Materials Select Sector SPDR Fund\n            \"XLY\",  # Consumer Discretionary Select Sector SPDR Fund\n            \"XLP\",  # Consumer Staples Select Sector SPDR Fund\n            \"XLU\",  # Utilities Select Sector SPDR Fund\n        ]\n\n        for symbol in self.symbols:\n            data = self.AddEquity(symbol, Resolution.Daily)\n            data.SetFeeModel(CustomFeeModel())\n            data.SetLeverage(5)\n\n            self.data[symbol] = self.ROC(symbol, self.period, Resolution.Daily)\n\n        self.data[self.symbols[0]].Updated += self.OnROCUpdated\n        self.recent_month = -1\n        self.rebalance_flag = False\n\n    def OnROCUpdated(self, sender, updated):\n        # set rebalance flag\n        if self.recent_month != self.Time.month:\n            self.recent_month = self.Time.month\n            self.rebalance_flag = True\n\n    def OnData(self, data):\n        if self.IsWarmingUp:\n            return\n\n        # rebalance once a month\n        if self.rebalance_flag:\n            self.rebalance_flag = False\n\n            sorted_by_momentum = sorted(\n                [\n                    x\n                    for x in self.data.items()\n                    if x[1].IsReady and x[0] in data and data[x[0]]\n                ],\n                key=lambda x: x[1].Current.Value,\n                reverse=True,\n            )\n            long = [x[0] for x in sorted_by_momentum[:3]]\n\n            # Trade execution.\n            invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n            for symbol in invested:\n                if symbol not in long:\n                    self.Liquidate(symbol)\n\n            for symbol in long:\n                self.SetHoldings(symbol, 1 / len(long))\n\n\n# Custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n"
  },
  {
    "path": "static/strategies/short-interest-effect-long-short-version.py",
    "content": "# https://quantpedia.com/strategies/short-interest-effect-long-short-version/\n#\n# All stocks from NYSE, AMEX, and NASDAQ are part of the investment universe. Stocks are then sorted each month into short-interest deciles based on\n# the ratio of short interest to shares outstanding. The investor then goes long on the decile with the lowest short ratio and short on the decile\n# with the highest short ratio. The portfolio is rebalanced monthly, and stocks in the portfolio are weighted equally.\n\nfrom AlgorithmImports import *\n\n\nclass ShortInterestEffect(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2010, 1, 1)\n        self.SetCash(100000)\n\n        # NOTE: We use only s&p 100 stocks so it's possible to fetch short interest data from quandl.\n        self.symbols = [\n            \"AAPL\",\n            \"MSFT\",\n            \"AMZN\",\n            \"FB\",\n            \"GOOGL\",\n            \"GOOG\",\n            \"JPM\",\n            \"JNJ\",\n            \"V\",\n            \"PG\",\n            \"XOM\",\n            \"UNH\",\n            \"BAC\",\n            \"MA\",\n            \"T\",\n            \"DIS\",\n            \"INTC\",\n            \"HD\",\n            \"VZ\",\n            \"MRK\",\n            \"PFE\",\n            \"CVX\",\n            \"KO\",\n            \"CMCSA\",\n            \"CSCO\",\n            \"PEP\",\n            \"WFC\",\n            \"C\",\n            \"BA\",\n            \"ADBE\",\n            \"WMT\",\n            \"CRM\",\n            \"MCD\",\n            \"MDT\",\n            \"BMY\",\n            \"ABT\",\n            \"NVDA\",\n            \"NFLX\",\n            \"AMGN\",\n            \"PM\",\n            \"PYPL\",\n            \"TMO\",\n            \"COST\",\n            \"ABBV\",\n            \"ACN\",\n            \"HON\",\n            \"NKE\",\n            \"UNP\",\n            \"UTX\",\n            \"NEE\",\n            \"IBM\",\n            \"TXN\",\n            \"AVGO\",\n            \"LLY\",\n            \"ORCL\",\n            \"LIN\",\n            \"SBUX\",\n            \"AMT\",\n            \"LMT\",\n            \"GE\",\n            \"MMM\",\n            \"DHR\",\n            \"QCOM\",\n            \"CVS\",\n            \"MO\",\n            \"LOW\",\n            \"FIS\",\n            \"AXP\",\n            \"BKNG\",\n            \"UPS\",\n            \"GILD\",\n            \"CHTR\",\n            \"CAT\",\n            \"MDLZ\",\n            \"GS\",\n            \"USB\",\n            \"CI\",\n            \"ANTM\",\n            \"BDX\",\n            \"TJX\",\n            \"ADP\",\n            \"TFC\",\n            \"CME\",\n            \"SPGI\",\n            \"COP\",\n            \"INTU\",\n            \"ISRG\",\n            \"CB\",\n            \"SO\",\n            \"D\",\n            \"FISV\",\n            \"PNC\",\n            \"DUK\",\n            \"SYK\",\n            \"ZTS\",\n            \"MS\",\n            \"RTN\",\n            \"AGN\",\n            \"BLK\",\n        ]\n\n        for symbol in self.symbols:\n            data = self.AddEquity(symbol, Resolution.Daily)\n            data.SetFeeModel(CustomFeeModel())\n            data.SetLeverage(5)\n\n            self.AddData(\n                QuandlFINRA_ShortVolume, \"FINRA/FNSQ_\" + symbol, Resolution.Daily\n            )\n\n        self.recent_month = -1\n\n    def OnData(self, data):\n        if self.recent_month == self.Time.month:\n            return\n        self.recent_month = self.Time.month\n\n        short_interest = {}\n        for symbol in self.symbols:\n            sym = \"FINRA/FNSQ_\" + symbol\n            if sym in data and data[sym] and symbol in data and data[symbol]:\n                short_vol = data[sym].GetProperty(\"SHORTVOLUME\")\n                total_vol = data[sym].GetProperty(\"TOTALVOLUME\")\n\n                short_interest[symbol] = short_vol / total_vol\n\n        long = []\n        short = []\n        if len(short_interest) >= 10:\n            sorted_by_short_interest = sorted(\n                short_interest.items(), key=lambda x: x[1], reverse=True\n            )\n            decile = int(len(sorted_by_short_interest) / 10)\n            long = [x[0] for x in sorted_by_short_interest[-decile:]]\n            short = [x[0] for x in sorted_by_short_interest[:decile]]\n\n        # trade execution\n        stocks_invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in long + short:\n                self.Liquidate(symbol)\n\n        for symbol in long:\n            if symbol in data and data[symbol]:\n                self.SetHoldings(symbol, 1 / len(long))\n        for symbol in short:\n            if symbol in data and data[symbol]:\n                self.SetHoldings(symbol, -1 / len(short))\n\n\nclass QuandlFINRA_ShortVolume(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = \"SHORTVOLUME\"  # also 'TOTALVOLUME' is accesible\n\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n"
  },
  {
    "path": "static/strategies/short-term-reversal-in-stocks.py",
    "content": "# region imports\nfrom AlgorithmImports import *\n\n# endregion\n# https://quantpedia.com/strategies/short-term-reversal-in-stocks/\n#\n# The investment universe consists of the 100 biggest companies by market capitalization.\n# The investor goes long on the ten stocks with the lowest performance in the previous week and\n# goes short on the ten stocks with the greatest performance of the prior month. The portfolio is rebalanced weekly.\n#\n# QC implementation changes:\n#   - Instead of all listed stocks, we first select 500 most liquid stock from QC as a first filter due to time complexity issues tied to whole universe filtering.\n#   - Then top 100 market cap stocks are used in momentum sorting.\n\n\nclass ShortTermReversalEffectinStocks(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.symbol = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n\n        self.coarse_count = 500\n        self.stock_selection = 10\n        self.top_by_market_cap_count = 100\n\n        self.period = 21\n\n        self.long = []\n        self.short = []\n\n        # Daily close data\n        self.data = {}\n\n        self.day = 1\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        self.Schedule.On(\n            self.DateRules.EveryDay(self.symbol),\n            self.TimeRules.AfterMarketOpen(self.symbol),\n            self.Selection,\n        )\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(5)\n\n    def CoarseSelectionFunction(self, coarse):\n        # Update the rolling window every day.\n        for stock in coarse:\n            symbol = stock.Symbol\n\n            # Store monthly price.\n            if symbol in self.data:\n                self.data[symbol].update(stock.AdjustedPrice)\n\n        if not self.selection_flag:\n            return Universe.Unchanged\n\n        selected = sorted(\n            [\n                x\n                for x in coarse\n                if x.HasFundamentalData and x.Market == \"usa\" and x.Price > 1\n            ],\n            key=lambda x: x.DollarVolume,\n            reverse=True,\n        )\n        selected = [x.Symbol for x in selected][: self.coarse_count]\n\n        # Warmup price rolling windows.\n        for symbol in selected:\n            if symbol in self.data:\n                continue\n\n            self.data[symbol] = SymbolData(self.period)\n            history = self.History(symbol, self.period, Resolution.Daily)\n            if history.empty:\n                self.Log(f\"Not enough data for {symbol} yet\")\n                continue\n            closes = history.loc[symbol].close\n            for time, close in closes.iteritems():\n                self.data[symbol].update(close)\n\n        return [x for x in selected if self.data[x].is_ready()]\n\n    def FineSelectionFunction(self, fine):\n        fine = [x for x in fine if x.MarketCap != 0]\n\n        sorted_by_market_cap = sorted(fine, key=lambda x: x.MarketCap, reverse=True)\n        top_by_market_cap = [\n            x.Symbol for x in sorted_by_market_cap[: self.top_by_market_cap_count]\n        ]\n\n        month_performances = {\n            symbol: self.data[symbol].monthly_return() for symbol in top_by_market_cap\n        }\n        week_performances = {\n            symbol: self.data[symbol].weekly_return() for symbol in top_by_market_cap\n        }\n\n        sorted_by_month_perf = [\n            x[0]\n            for x in sorted(\n                month_performances.items(), key=lambda item: item[1], reverse=True\n            )\n        ]\n        sorted_by_week_perf = [\n            x[0] for x in sorted(week_performances.items(), key=lambda item: item[1])\n        ]\n\n        self.long = sorted_by_week_perf[: self.stock_selection]\n\n        for symbol in sorted_by_month_perf:  # Month performances are sorted descending\n            if symbol not in self.long:\n                self.short.append(symbol)\n\n            if len(self.short) == 10:\n                break\n\n        return self.long + self.short\n\n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n\n        invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in invested:\n            if symbol not in self.long + self.short:\n                self.Liquidate(symbol)\n\n        # Leveraged portfolio - 100% long, 100% short.\n        for symbol in self.long:\n            if (\n                self.Securities[symbol].Price != 0\n                and self.Securities[symbol].IsTradable\n            ):\n                self.SetHoldings(symbol, 1 / len(self.long))\n\n        for symbol in self.short:\n            if (\n                self.Securities[symbol].Price != 0\n                and self.Securities[symbol].IsTradable\n            ):\n                self.SetHoldings(symbol, -1 / len(self.short))\n\n        self.long.clear()\n        self.short.clear()\n\n    def Selection(self):\n        if self.day == 5:\n            self.selection_flag = True\n\n        self.day += 1\n        if self.day > 5:\n            self.day = 1\n\n\nclass SymbolData:\n    def __init__(self, period):\n        self.closes = RollingWindow[float](period)\n        self.period = period\n\n    def update(self, close):\n        self.closes.Add(close)\n\n    def is_ready(self) -> bool:\n        return self.closes.IsReady\n\n    def weekly_return(self) -> float:\n        return self.closes[0] / self.closes[5] - 1\n\n    def monthly_return(self) -> float:\n        return self.closes[0] / self.closes[self.period - 1] - 1\n\n\n# Custom fee model\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n"
  },
  {
    "path": "static/strategies/short-term-reversal-with-futures.py",
    "content": "# region imports\nfrom AlgorithmImports import *\n\n# endregion\n# https://quantpedia.com/strategies/short-term-reversal-with-futures/\n#\n# The investment universe consists of 24 types of US futures contracts (4 currencies, 5 financials, 8 agricultural, 7 commodities).\n# A weekly time frame is used – a Wednesday- Wednesday interval. The contract closest to expiration is used, except within the delivery\n# month, in which the second-nearest contract is used. Rolling into the second nearest contract is done at the beginning of the delivery month.\n# The contract is defined as the high- (low-) volume contract if the contract’s volume changes between period from t-1 to t and period from t-2\n# to t-1 is above (below) the median volume change of all contracts (weekly trading volume is detrended by dividing the trading volume by its\n# sample mean to make the volume measure comparable across markets). All contracts are also assigned to either high-open interest (top 50% of\n# changes in open interest) or low-open interest groups (bottom 50% of changes in open interest) based on lagged changes in open interest between\n# the period from t-1 to t and period from t-2 to t-1. The investor goes long (short) on futures from the high-volume, low-open interest group\n# with the lowest (greatest) returns in the previous week. The weight of each contract is proportional to the difference between the return\n# of the contract over the past one week and the equal-weighted average of returns on the N (number of contracts in a group) contracts during that period.\n\nfrom collections import deque\nimport numpy as np\n\n\nclass ShortTermReversal(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2010, 1, 1)\n        self.SetCash(100000)\n\n        symbols: dict = {\n            \"CME_S1\": Futures.Grains.Soybeans,\n            \"CME_W1\": Futures.Grains.Wheat,\n            \"CME_BO1\": Futures.Grains.SoybeanOil,\n            \"CME_C1\": Futures.Grains.Corn,\n            \"CME_LC1\": Futures.Meats.LiveCattle,\n            \"CME_FC1\": Futures.Meats.FeederCattle,\n            \"CME_KW2\": Futures.Grains.Wheat,\n            \"ICE_CC1\": Futures.Softs.Cocoa,\n            \"ICE_SB1\": Futures.Softs.Sugar11CME,\n            \"CME_GC1\": Futures.Metals.Gold,\n            \"CME_SI1\": Futures.Metals.Silver,\n            \"CME_PL1\": Futures.Metals.Platinum,\n            \"CME_RB1\": Futures.Energies.Gasoline,\n            \"ICE_WT1\": Futures.Energies.CrudeOilWTI,\n            \"ICE_O1\": Futures.Energies.HeatingOil,\n            \"CME_BP1\": Futures.Currencies.GBP,\n            \"CME_EC1\": Futures.Currencies.EUR,\n            \"CME_JY1\": Futures.Currencies.JPY,\n            \"CME_SF1\": Futures.Currencies.CHF,\n            \"CME_ES1\": Futures.Indices.SP500EMini,\n            \"CME_TY1\": Futures.Financials.Y10TreasuryNote,\n            \"CME_FV1\": Futures.Financials.Y5TreasuryNote,\n        }\n\n        self.period: int = 14\n        self.SetWarmUp(self.period, Resolution.Daily)\n\n        self.futures_info: dict = {}\n        self.min_expiration_days: int = 2\n        self.max_expiration_days: int = 360\n\n        # daily close, volume and open interest data\n        self.data: dict = {}\n\n        for qp_symbol, qc_future in symbols.items():\n            # QP futures\n            data: Security = self.AddData(\n                QuantpediaFutures, qp_symbol, Resolution.Daily\n            )\n            data.SetFeeModel(CustomFeeModel())\n            data.SetLeverage(5)\n            self.data[data.Symbol] = deque(maxlen=self.period)\n\n            # QC futures\n            future: Future = self.AddFuture(\n                qc_future,\n                Resolution.Daily,\n                dataNormalizationMode=DataNormalizationMode.Raw,\n            )\n            future.SetFilter(\n                timedelta(days=self.min_expiration_days),\n                timedelta(days=self.max_expiration_days),\n            )\n\n            self.futures_info[future.Symbol.Value] = FuturesInfo(data.Symbol)\n\n        self.recent_month: int = -1\n\n    def find_and_update_contracts(self, futures_chain, symbol) -> None:\n        near_contract: FuturesContract = None\n\n        if symbol in futures_chain:\n            contracts: list = [\n                contract\n                for contract in futures_chain[symbol]\n                if contract.Expiry.date() > self.Time.date()\n            ]\n\n            if len(contracts) >= 1:\n                contracts: list = sorted(\n                    contracts, key=lambda x: x.Expiry, reverse=False\n                )\n                near_contract = contracts[0]\n\n        self.futures_info[symbol].update_contracts(near_contract)\n\n    def OnData(self, data):\n        if data.FutureChains.Count > 0:\n            for symbol, futures_info in self.futures_info.items():\n                # check if near contract is expired or is not initialized\n                if not futures_info.is_initialized() or (\n                    futures_info.is_initialized()\n                    and futures_info.near_contract.Expiry.date() == self.Time.date()\n                ):\n                    self.find_and_update_contracts(data.FutureChains, symbol)\n\n        rebalance_flag: bool = False\n        ret_volume_oi_data: dict[Symbol, tuple] = {}\n\n        # roll return calculation\n        for symbol, futures_info in self.futures_info.items():\n            # futures data is present in the algorithm\n            if (\n                futures_info.quantpedia_future in data\n                and data[futures_info.quantpedia_future]\n            ):\n                if futures_info.is_initialized():\n                    near_c: FuturesContract = futures_info.near_contract\n\n                    if self.Securities.ContainsKey(near_c.Symbol):\n                        if futures_info.is_initialized():\n                            # store daily data\n                            price: float = data[futures_info.quantpedia_future].Value\n                            vol: int = self.Securities[near_c.Symbol].Volume\n                            oi: int = self.Securities[near_c.Symbol].OpenInterest\n\n                            if price != 0 and vol != 0 and oi != 0:\n                                self.data[futures_info.quantpedia_future].append(\n                                    (price, vol, oi)\n                                )\n\n                    # new month rebalance\n                    if self.Time.month != self.recent_month and not self.IsWarmingUp:\n                        self.recent_month = self.Time.month\n                        rebalance_flag = True\n\n                    if rebalance_flag:\n                        if (\n                            len(self.data[futures_info.quantpedia_future])\n                            == self.data[futures_info.quantpedia_future].maxlen\n                        ):\n                            # performance\n                            prices: list[float] = [\n                                x[0] for x in self.data[futures_info.quantpedia_future]\n                            ]\n                            half: list[float] = int(len(prices) / 2)\n                            prices: list[float] = prices[-half:]\n                            ret: float = prices[-1] / prices[0] - 1\n\n                            # volume change\n                            volumes: list[int] = [\n                                x[1] for x in self.data[futures_info.quantpedia_future]\n                            ]\n                            volumes_t1: list[int] = volumes[-half:]\n                            t1_vol_mean: float = np.mean(volumes_t1)\n                            t1_vol_total: float = sum(volumes_t1) / t1_vol_mean\n                            volumes_t2: list[int] = volumes[:half]\n                            t2_vol_mean: float = np.mean(volumes_t2)\n                            t2_vol_total: float = sum(volumes_t2) / t2_vol_mean\n                            volume_weekly_diff: float = t1_vol_total - t2_vol_total\n\n                            # open interest change\n                            interests: list[int] = [\n                                x[2] for x in self.data[futures_info.quantpedia_future]\n                            ]\n                            t1_oi: list[int] = interests[-half:]\n                            t1_oi_total: float = sum(t1_oi)\n                            t2_oi: list[int] = interests[:half]\n                            t2_oi_total: float = sum(t2_oi)\n                            oi_weekly_diff: float = t1_oi_total - t2_oi_total\n\n                            # store weekly diff data\n                            ret_volume_oi_data[futures_info.quantpedia_future] = (\n                                ret,\n                                volume_weekly_diff,\n                                oi_weekly_diff,\n                            )\n\n        if rebalance_flag:\n            weight: dict[Symbol, float] = {}\n\n            if len(ret_volume_oi_data) > 4:\n                volume_sorted: list = sorted(\n                    ret_volume_oi_data.items(), key=lambda x: x[1][1], reverse=True\n                )\n                half: int = int(len(volume_sorted) / 2)\n                high_volume: list = [x for x in volume_sorted[:half]]\n\n                open_interest_sorted: list = sorted(\n                    ret_volume_oi_data.items(), key=lambda x: x[1][2], reverse=True\n                )\n                half = int(len(open_interest_sorted) / 2)\n                low_oi: list = [x for x in open_interest_sorted[-half:]]\n\n                filtered: list = [x for x in high_volume if x in low_oi]\n                filtered_by_return: list = sorted(\n                    filtered, key=lambda x: x[0], reverse=True\n                )\n                half = int(len(filtered_by_return) / 2)\n\n                long: list[Symbol] = filtered_by_return[-half:]\n                short: list[Symbol] = filtered_by_return[:half]\n\n                if len(long + short) >= 2:\n                    # return weighting\n                    diff: dict[Symbol, float] = {}\n                    avg_ret: float = np.average([x[1][0] for x in long + short])\n\n                    for symbol, ret_volume_oi in long + short:\n                        diff[symbol] = ret_volume_oi[0] - avg_ret\n\n                    total_diff: float = sum([abs(x[1]) for x in diff.items()])\n                    long_symbols: list[Symbol] = [x[0] for x in long]\n\n                    if total_diff != 0:\n                        for symbol, data in long + short:\n                            if symbol in long_symbols:\n                                weight[symbol] = diff[symbol] / total_diff\n                            else:\n                                weight[symbol] = -diff[symbol] / total_diff\n\n            # trade execution\n            invested: list[Symbol] = [x.Key for x in self.Portfolio if x.Value.Invested]\n            for symbol in invested:\n                if symbol not in weight:\n                    self.Liquidate(symbol)\n\n            for symbol, w in weight.items():\n                self.SetHoldings(symbol, w)\n\n\nclass FuturesInfo:\n    def __init__(self, quantpedia_future: Symbol) -> None:\n        self.quantpedia_future: Symbol = quantpedia_future\n        self.near_contract: FuturesContract = None\n\n    def update_contracts(self, near_contract: FuturesContract) -> None:\n        self.near_contract = near_contract\n\n    def is_initialized(self) -> bool:\n        return self.near_contract is not None\n\n\n# Custom fee model.\nclass CustomFeeModel:\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\";\")\n\n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data[\"back_adjusted\"] = float(split[1])\n        data[\"spliced\"] = float(split[2])\n        data.Value = float(split[1])\n\n        return data\n"
  },
  {
    "path": "static/strategies/skewness-effect-in-commodities.py",
    "content": "# https://quantpedia.com/strategies/skewness-effect-in-commodities/\n#\n# The investment universe consists of 27 futures contracts on commodities. Each month, investor calculates skewness (3rd moment of returns)\n# from daily returns from data going 12 months into the past for all futures. Commodities are then sorted into quintiles and investor goes\n# long quintile containing the commodities with the 20% lowest total skewness and short quintile containing the commodities with the 20% highest\n# total skewness (over a ranking period of 12 months). The resultant portfolio is equally weighted and rebalanced each month.\n\nimport numpy as np\nfrom AlgorithmImports import *\nfrom scipy.stats import skew\n\n\nclass SkewnessEffect(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.symbols = [\n            \"CME_S1\",  # Soybean Futures, Continuous Contract\n            \"CME_W1\",  # Wheat Futures, Continuous Contract\n            \"CME_SM1\",  # Soybean Meal Futures, Continuous Contract\n            \"CME_BO1\",  # Soybean Oil Futures, Continuous Contract\n            \"CME_C1\",  # Corn Futures, Continuous Contract\n            \"CME_O1\",  # Oats Futures, Continuous Contract\n            \"CME_LC1\",  # Live Cattle Futures, Continuous Contract\n            \"CME_FC1\",  # Feeder Cattle Futures, Continuous Contract\n            \"CME_LN1\",  # Lean Hog Futures, Continuous Contract\n            \"CME_GC1\",  # Gold Futures, Continuous Contract\n            \"CME_SI1\",  # Silver Futures, Continuous Contract\n            \"CME_PL1\",  # Platinum Futures, Continuous Contract\n            \"CME_CL1\",  # Crude Oil Futures, Continuous Contract\n            \"CME_HG1\",  # Copper Futures, Continuous Contract\n            \"CME_LB1\",  # Random Length Lumber Futures, Continuous Contract\n            # \"CME_NG1\",  # Natural Gas (Henry Hub) Physical Futures, Continuous Contract\n            \"CME_PA1\",  # Palladium Futures, Continuous Contract\n            \"CME_RR1\",  # Rough Rice Futures, Continuous Contract\n            \"CME_DA1\",  # Class III Milk Futures\n            \"ICE_RS1\",  # Canola Futures, Continuous Contract\n            \"ICE_GO1\",  # Gas Oil Futures, Continuous Contract\n            \"CME_RB2\",  # Gasoline Futures, Continuous Contract\n            \"CME_KW2\",  # Wheat Kansas, Continuous Contract\n            \"ICE_WT1\",  # WTI Crude Futures, Continuous Contract\n            \"ICE_CC1\",  # Cocoa Futures, Continuous Contract\n            \"ICE_CT1\",  # Cotton No. 2 Futures, Continuous Contract\n            \"ICE_KC1\",  # Coffee C Futures, Continuous Contract\n            \"ICE_O1\",  # Heating Oil Futures, Continuous Contract\n            \"ICE_OJ1\",  # Orange Juice Futures, Continuous Contract\n            \"ICE_SB1\",  # Sugar No. 11 Futures, Continuous Contract\n        ]\n\n        self.period = 12 * 21\n        self.quantile = 5\n        self.SetWarmup(self.period)\n        self.data = {}\n\n        for symbol in self.symbols:\n            data = self.AddData(QuantpediaFutures, symbol, Resolution.Daily)\n            data.SetFeeModel(CustomFeeModel())\n            data.SetLeverage(5)\n\n            self.data[symbol] = RollingWindow[float](self.period)\n\n        self.Schedule.On(\n            self.DateRules.MonthStart(self.symbols[0]),\n            self.TimeRules.At(0, 0),\n            self.Rebalance,\n        )\n\n    def OnData(self, data):\n        for symbol in self.symbols:\n            symbol_obj = self.Symbol(symbol)\n            if symbol_obj in data.Keys:\n                price = data[symbol_obj].Value\n                if price != 0:\n                    self.data[symbol].Add(price)\n\n    def Rebalance(self):\n        if self.IsWarmingUp:\n            return\n\n        # Skewness calculation\n        skewness_data = {}\n        for symbol in self.symbols:\n            if self.data[symbol].IsReady:\n                if (\n                    self.Securities[symbol].GetLastData()\n                    and (\n                        self.Time.date()\n                        - self.Securities[symbol].GetLastData().Time.date()\n                    ).days\n                    < 5\n                ):\n                    prices = np.array([x for x in self.data[symbol]])\n                    returns = (prices[:-1] / prices[1:]) - 1\n                    if len(returns) == self.period - 1:\n                        # NOTE: Manual skewness calculation example\n                        # avg = np.average(returns)\n                        # std = np.std(returns)\n                        # skewness = (sum(np.power((x - avg), 3) for x in returns)) / ((self.return_history[symbol].maxlen-1) * np.power(std, 3))\n                        skewness_data[symbol] = skew(returns)\n\n        long = []\n        short = []\n        if len(skewness_data) >= self.quantile:\n            # Skewness sorting\n            sorted_by_skewness = sorted(\n                skewness_data.items(), key=lambda x: x[1], reverse=True\n            )\n            quintile = int(len(sorted_by_skewness) / self.quantile)\n            long = [x[0] for x in sorted_by_skewness[-quintile:]]\n            short = [x[0] for x in sorted_by_skewness[:quintile]]\n\n        # Trade execution\n        invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]\n        for symbol in invested:\n            if symbol not in long + short:\n                self.Liquidate(symbol)\n\n        for symbol in long:\n            self.SetHoldings(symbol, 1 / len(long))\n        for symbol in short:\n            self.SetHoldings(symbol, -1 / len(short))\n\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\";\")\n\n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data[\"back_adjusted\"] = float(split[1])\n        data[\"spliced\"] = float(split[2])\n        data.Value = float(split[1])\n\n        return data\n\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n"
  },
  {
    "path": "static/strategies/small-capitalization-stocks-premium-anomaly.py",
    "content": "# https://quantpedia.com/strategies/small-capitalization-stocks-premium-anomaly/\n#\n# The investment universe contains all NYSE, AMEX, and NASDAQ stocks. Decile portfolios are formed based on the market capitalization\n# of stocks. To capture “size” effect, SMB portfolio goes long small stocks (lowest decile) and short big stocks (highest decile).\n#\n# QC implementation changes:\n#   - Instead of all listed stock, we select top 3000 stocks by market cap from QC stock universe.\n\nfrom AlgorithmImports import *\n\nclass ValueBooktoMarketFactor(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000) \n\n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        \n        self.coarse_count = 3000\n        \n        self.long = []\n        self.short = []\n        \n        self.month = 12\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        \n        self.Schedule.On(self.DateRules.MonthEnd(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Selection)\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(10)\n\n    def CoarseSelectionFunction(self, coarse):\n        if not self.selection_flag:\n            return Universe.Unchanged\n        \n        selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa']\n        return selected\n    \n    def FineSelectionFunction(self, fine):\n        sorted_by_market_cap = sorted([x for x in fine if x.MarketCap != 0 and  \\\n                                ((x.SecurityReference.ExchangeId == \"NYS\") or (x.SecurityReference.ExchangeId == \"NAS\") or (x.SecurityReference.ExchangeId == \"ASE\"))],    \\\n                                key = lambda x:x.MarketCap, reverse=True)\n        top_by_market_cap = [x for x in sorted_by_market_cap[:self.coarse_count]]\n\n        quintile = int(len(top_by_market_cap) / 5)\n        self.long = [i.Symbol for i in top_by_market_cap[-quintile:]]\n        self.short = [i.Symbol for i in top_by_market_cap[:quintile]]\n        \n        return self.long + self.short\n    \n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n        \n        # Trade execution.\n        long_count = len(self.long)\n        short_count = len(self.short)\n        \n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.long + self.short:\n                self.Liquidate(symbol)\n        \n        # Leveraged portfolio - 100% long, 100% short. \n        for symbol in self.long:\n            self.SetHoldings(symbol, 1 / long_count)\n\n        for symbol in self.short:\n            self.SetHoldings(symbol, -1 / short_count)\n\n        self.long.clear()\n        self.short.clear()\n    \n    def Selection(self):\n        if self.month == 12:\n            self.selection_flag = True\n        \n        self.month += 1\n        if self.month > 12:\n            self.month = 1\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/soccer-clubs-stocks-arbitrage.py",
    "content": "# https://quantpedia.com/strategies/soccer-clubs-stocks-arbitrage/\n#\n# The investment universe consists of liquid soccer clubs’ stocks that are publicly traded.\n# The investor then sells short stocks of clubs that play UEFA Championship matches (or other important matches)\n# at the end of the business day before the match. Stocks are held for one day,\n# and the portfolio of stocks is equally weighted (if there are multiple clubs with matches that day).\n#\n# QC Implementation:\n\n#region imports\nfrom AlgorithmImports import *\n#endregion\n\nclass SoccerClubsStocksArbitrage(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n        \n        self.tickers = [\n            'FCPP',  # Futebol Clube Do Porto\n            'SPSO',  # Sporting Clube De Portugal\n            'SLBEN', # Benfica\n            'LAZI',  # Lazio\n            'ASR',   # AS Rome\n            'AJAX',  # AJAX\n            'JUVE',  # Juventus\n            'MANU',  # Manchester United\n            'BVB',   # Dortmund\n            'CCP',   # Celtic\n            # 'BOLA' # Bali Bintang Sejahtera Tbk PT\n        ]\n        \n        self.match_dates = {}\n        \n        for ticker in self.tickers:\n            security = self.AddData(QuantpediaSoccer, ticker, Resolution.Daily)\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(5)\n            \n        csv_string_file = self.Download('data.quantpedia.com/backtesting_data/equity/soccer/soccer_matches.csv')\n        lines = csv_string_file.split('\\r\\n')\n        for line in lines:\n            line_split = line.split(';')\n            date = datetime.strptime(line_split[0], \"%d.%m.%Y\").date()\n            \n            self.match_dates[date] = []\n            for i in range(1, len(line_split)):\n                ticker = line_split[i]\n                self.match_dates[date].append(ticker)\n        \n    def OnData(self, data):\n        self.Liquidate()\n        \n        short = []\n        \n        # Looking for todays date, because only daily closes are traded.\n        today = (self.Time - timedelta(days=1)).date()\n        \n        if today in self.match_dates:\n            for ticker in self.tickers:\n                if ticker in self.match_dates[today] and ticker in data:\n                    short.append(ticker)\n                    \n        for ticker in short:\n            self.SetHoldings(ticker, -1 / len(short))\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaSoccer(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/equity/soccer/{0}.csv\".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaSoccer()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n        split = line.split(';')\n        \n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data['price'] = float(split[1])\n        data.Value = float(split[1])\n\n        return data\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/synthetic-lending-rates-predict-subsequent-market-return.py",
    "content": "# https://quantpedia.com/strategies/synthetic-lending-rates-predict-subsequent-market-return/\n#\n# The investment universe consists of SPY ETF. Synthetic shorting costs data are obtained from Borrow Intensity Indicators by the CBOE (and includes 4877 stocks/ETFs). \n# The paper utilizes the constant maturities of 45 days. Intraday SPY data are obtained from FirstRate Data. The aggregate (mean) borrow intensity is calculated as equally weighted borrow intensity of each stock/ETF in the sample at day t.\n# The shorting costs data are estimated at a timestamp of 15:57. Calculate the change in the aggregate intensity at day t as the difference of aggregate borrowing intensity at day t and t-1.\n# Buy the SPY ETF at 15:59 if the difference is positive and short the SPY if the difference is negative. The positions are held for one day and are closed at 15:58 at next day.\n# \n# QC Implementation changes:\n#   - Signal calculation and trade opening is done each day at 15:59.\n\n#region imports\nfrom AlgorithmImports import *\n#endregion\n\nclass SyntheticLendingRatesPredictSubsequentMarketReturn(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2016, 1, 1)\n        self.SetCash(100000)\n\n        self.spy_symbol:Symbol = self.AddEquity('SPY', Resolution.Minute).Symbol  \n\n        self.lending_data_symbol:Symbol = self.AddData(\n            QuantpediaLendingRates,\n            'lending_rate', \n            Resolution.Minute).Symbol\n\n        self.last_lending_mean = None          \n\n    def OnData(self, data: Slice):\n        curr_time:datetime.datetime = self.Time\n        \n        # liquidate on 15:58\n        if curr_time.hour == 15 and curr_time.minute == 58:\n            self.Liquidate(self.spy_symbol) \n\n        # lending rate data came in\n        if self.lending_data_symbol in data and data[self.lending_data_symbol]:\n            curr_lending_mean:float = data[self.lending_data_symbol].Value\n\n            if self.last_lending_mean:\n                # calculate daily change in lending rate\n                diff:float = curr_lending_mean - self.last_lending_mean\n\n                if diff > 0:\n                    self.SetHoldings(self.spy_symbol, 1)\n                else:\n                    self.SetHoldings(self.spy_symbol, -1)\n\n            self.last_lending_mean = curr_lending_mean    \n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaLendingRates(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/options/lending_rates_day_close_matur_45_days.csv\".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    def Reader(self, config, line, date, isLiveMode):\n        data:QuantpediaLendingRates = QuantpediaLendingRates()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n\n        split:list = line.split(';')\n\n        datetime_str:str = split[0] + ', 15:59'\n        \n        data.Time = datetime.strptime(datetime_str, \"%Y-%m-%d, %H:%M\")\n        valid_values:list = list(filter(lambda value: value != '', split[1:]))\n        valid_values:list = list(map(lambda str_value: float(str_value), valid_values))\n        data.Value = np.mean(valid_values)\n\n        return data"
  },
  {
    "path": "static/strategies/term-structure-effect-in-commodities.py",
    "content": "# https://quantpedia.com/strategies/term-structure-effect-in-commodities/\n#\n# This simple strategy buys each month the 20% of commodities with the highest roll-returns and shorts the 20% of commodities with the lowest \n# roll-returns and holds the long-short positions for one month. The contracts in each quintile are equally-weighted. \n# The investment universe is all commodity futures contracts.\n#\n# QC implementation:\n\nimport numpy as np\nfrom datetime import time\nfrom AlgorithmImports import *\n\nclass TermStructure(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2009, 1, 1)\n        self.SetCash(100000)\n\n        symbols = {\n                        'CME_S1': Futures.Grains.Soybeans,\n                        'CME_W1' : Futures.Grains.Wheat,\n                        'CME_SM1' : Futures.Grains.SoybeanMeal,\n                        'CME_C1' : Futures.Grains.Corn,\n                        'CME_O1' : Futures.Grains.Oats,\n                        'CME_LC1' : Futures.Meats.LiveCattle,\n                        'CME_FC1' : Futures.Meats.FeederCattle,\n                        'CME_LN1' : Futures.Meats.LeanHogs,\n                        'CME_GC1' : Futures.Metals.Gold,\n                        'CME_SI1' : Futures.Metals.Silver,\n                        'CME_PL1' : Futures.Metals.Platinum,\n\n                        'CME_HG1' : Futures.Metals.Copper,\n                        'CME_LB1' : Futures.Forestry.RandomLengthLumber,\n                        'CME_NG1' : Futures.Energies.NaturalGas,\n                        'CME_PA1' : Futures.Metals.Palladium,\n                        'CME_DA1' : Futures.Dairy.ClassIIIMilk,\n                        \n                        'CME_RB1' : Futures.Energies.Gasoline,\n                        'ICE_WT1' : Futures.Energies.CrudeOilWTI,\n                        'ICE_CC1' : Futures.Softs.Cocoa,\n                        'ICE_O1' : Futures.Energies.HeatingOil,\n                        'ICE_SB1' : Futures.Softs.Sugar11CME,\n                        }\n    \n        self.futures_info:dict = {}\n        self.quantile:int = 5\n        self.min_expiration_days:int = 2\n        self.max_expiration_days:int = 360\n        \n        self.price_data:dict[Symbol, RollingWindow] = {}\n        self.period:int = 60\n        self.SetWarmup(self.period, Resolution.Daily)\n        \n        for qp_symbol, qc_future in symbols.items():\n            # QP futures\n            data:Security = self.AddData(QuantpediaFutures, qp_symbol, Resolution.Daily)\n            data.SetFeeModel(CustomFeeModel())\n            data.SetLeverage(5)\n            self.price_data[data.Symbol] = RollingWindow[float](self.period)\n            \n            # QC futures\n            future:Future = self.AddFuture(qc_future, Resolution.Daily, dataNormalizationMode=DataNormalizationMode.Raw)\n            future.SetFilter(timedelta(days=self.min_expiration_days), timedelta(days=self.max_expiration_days))\n            self.futures_info[future.Symbol.Value] = FuturesInfo(data.Symbol)\n        \n        self.recent_month:int = -1\n\n    def find_and_update_contracts(self, futures_chain, symbol) -> None:\n        near_contract:FuturesContract = None\n        dist_contract:FuturesContract = None\n\n        if symbol in futures_chain:\n            contracts:list = [contract for contract in futures_chain[symbol] if contract.Expiry.date() > self.Time.date()]\n\n            if len(contracts) >= 2:\n                contracts:list = sorted(contracts, key=lambda x: x.Expiry, reverse=False)\n                near_contract = contracts[0]\n                dist_contract = contracts[1]\n\n        self.futures_info[symbol].update_contracts(near_contract, dist_contract)\n\n    def OnData(self, data):\n        if data.FutureChains.Count > 0:\n            for symbol, futures_info in self.futures_info.items():\n                # check if near contract is expired or is not initialized\n                if not futures_info.is_initialized() or \\\n                    (futures_info.is_initialized() and futures_info.near_contract.Expiry.date() == self.Time.date()):\n                    self.find_and_update_contracts(data.FutureChains, symbol)\n        \n        roll_return:dict[Symbol, float] = {}\n        rebalance_flag:bool = False\n\n        # roll return calculation\n        for symbol, futures_info in self.futures_info.items():\n            # futures data is present in the algorithm\n            if futures_info.quantpedia_future in data and data[futures_info.quantpedia_future]:\n                # store daily data\n                self.price_data[futures_info.quantpedia_future].Add(data[futures_info.quantpedia_future].Value)\n                if not self.price_data[futures_info.quantpedia_future].IsReady:\n                    continue\n\n                # new month rebalance\n                if self.Time.month != self.recent_month and not self.IsWarmingUp:\n                    self.recent_month = self.Time.month\n                    rebalance_flag = True\n\n                if rebalance_flag:\n                    if futures_info.is_initialized():\n                        near_c:FuturesContract = futures_info.near_contract\n                        dist_c:FuturesContract = futures_info.distant_contract\n                        if self.Securities.ContainsKey(near_c.Symbol) and self.Securities.ContainsKey(dist_c.Symbol):\n                            raw_price1:float = self.Securities[near_c.Symbol].Close * self.Securities[symbol].SymbolProperties.PriceMagnifier\n                            raw_price2:float = self.Securities[dist_c.Symbol].Close * self.Securities[symbol].SymbolProperties.PriceMagnifier\n\n                            if raw_price1 != 0 and raw_price2 != 0:\n                                roll_return[futures_info.quantpedia_future] = raw_price1 / raw_price2 - 1\n\n        if rebalance_flag:\n            weights:dict[Symbol, float] = {}\n            \n            long:list[Symbol] = []\n            short:list[Symbol] = []\n            if len(roll_return) >= self.quantile:\n\n                # roll return sorting\n                sorted_by_roll:list = sorted(roll_return.items(), key = lambda x: x[1], reverse=True)\n                quantile:int = int(len(sorted_by_roll) / self.quantile)\n                long = [x[0] for x in sorted_by_roll[:quantile]]\n                short = [x[0] for x in sorted_by_roll[-quantile:]]\n\n            # trade execution\n            invested:list[Symbol] = [x.Key for x in self.Portfolio if x.Value.Invested]\n            for symbol in invested:\n                if symbol not in long + short:\n                    self.Liquidate(symbol)\n\n            for symbol in long:\n                self.SetHoldings(symbol, 1 / len(long))\n            \n            for symbol in short:\n                self.SetHoldings(symbol, -1 / len(short))\n\nclass FuturesInfo():\n    def __init__(self, quantpedia_future:Symbol) -> None:\n        self.quantpedia_future:Symbol = quantpedia_future\n        self.near_contract:FuturesContract = None\n        self.distant_contract:FuturesContract = None\n    \n    def update_contracts(self, near_contract:FuturesContract, distant_contract:FuturesContract) -> None:\n        self.near_contract = near_contract\n        self.distant_contract = distant_contract\n    \n    def is_initialized(self) -> bool:\n        return self.near_contract is not None and self.distant_contract is not None\n    \n# Custom fee model.\nclass CustomFeeModel():\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n        split = line.split(';')\n        \n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data['back_adjusted'] = float(split[1])\n        data['spliced'] = float(split[2])\n        data.Value = float(split[1])\n\n        return data"
  },
  {
    "path": "static/strategies/time-series-momentum-effect.py",
    "content": "# https://quantpedia.com/strategies/time-series-momentum-effect/\n#\n# The investment universe consists of 24 commodity futures, 12 cross-currency pairs (with 9 underlying currencies), 9 developed equity indices, and 13 developed\n# government bond futures.\n# Every month, the investor considers whether the excess return of each asset over the past 12 months is positive or negative and goes long on the contract if it is\n# positive and short if negative. The position size is set to be inversely proportional to the instrument’s volatility. A univariate GARCH model is used to estimated\n# ex-ante volatility in the source paper. However, other simple models could probably be easily used with good results (for example, the easiest one would be using\n# historical volatility instead of estimated volatility). The portfolio is rebalanced monthly.\n#\n# QC implementation changes:\n#   - instead of GARCH model volatility, we have used simple historical volatility.\n\nfrom math import sqrt\nfrom AlgorithmImports import *\nimport numpy as np\nimport pandas as pd\n\n\nclass TimeSeriesMomentum(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(10000000)\n\n        self.symbols = [\n            \"CME_S1\",  # Soybean Futures, Continuous Contract\n            \"CME_W1\",  # Wheat Futures, Continuous Contract\n            \"CME_SM1\",  # Soybean Meal Futures, Continuous Contract\n            \"CME_BO1\",  # Soybean Oil Futures, Continuous Contract\n            \"CME_C1\",  # Corn Futures, Continuous Contract\n            \"CME_O1\",  # Oats Futures, Continuous Contract\n            \"CME_LC1\",  # Live Cattle Futures, Continuous Contract\n            \"CME_FC1\",  # Feeder Cattle Futures, Continuous Contract\n            \"CME_LN1\",  # Lean Hog Futures, Continuous Contract\n            \"CME_GC1\",  # Gold Futures, Continuous Contract\n            \"CME_SI1\",  # Silver Futures, Continuous Contract\n            \"CME_PL1\",  # Platinum Futures, Continuous Contract\n            \"CME_CL1\",  # Crude Oil Futures, Continuous Contract\n            \"CME_HG1\",  # Copper Futures, Continuous Contract\n            \"CME_LB1\",  # Random Length Lumber Futures, Continuous Contract\n            \"CME_NG1\",  # Natural Gas (Henry Hub) Physical Futures, Continuous Contract\n            \"CME_PA1\",  # Palladium Futures, Continuous Contract\n            \"CME_RR1\",  # Rough Rice Futures, Continuous Contract\n            \"CME_DA1\",  # Class III Milk Futures\n            \"CME_RB1\",  # Gasoline Futures, Continuous Contract\n            \"CME_KW1\",  # Wheat Kansas, Continuous Contract\n            \"ICE_CC1\",  # Cocoa Futures, Continuous Contract\n            \"ICE_CT1\",  # Cotton No. 2 Futures, Continuous Contract\n            \"ICE_KC1\",  # Coffee C Futures, Continuous Contract\n            \"ICE_O1\",  # Heating Oil Futures, Continuous Contract\n            \"ICE_OJ1\",  # Orange Juice Futures, Continuous Contract\n            \"ICE_SB1\",  # Sugar No. 11 Futures, Continuous Contract\n            \"ICE_RS1\",  # Canola Futures, Continuous Contract\n            \"ICE_GO1\",  # Gas Oil Futures, Continuous Contract\n            \"ICE_WT1\",  # WTI Crude Futures, Continuous Contract\n            \"CME_AD1\",  # Australian Dollar Futures, Continuous Contract #1\n            \"CME_BP1\",  # British Pound Futures, Continuous Contract #1\n            \"CME_CD1\",  # Canadian Dollar Futures, Continuous Contract #1\n            \"CME_EC1\",  # Euro FX Futures, Continuous Contract #1\n            \"CME_JY1\",  # Japanese Yen Futures, Continuous Contract #1\n            \"CME_MP1\",  # Mexican Peso Futures, Continuous Contract #1\n            \"CME_NE1\",  # New Zealand Dollar Futures, Continuous Contract #1\n            \"CME_SF1\",  # Swiss Franc Futures, Continuous Contract #1\n            \"ICE_DX1\",  # US Dollar Index Futures, Continuous Contract #1\n            \"CME_NQ1\",  # E-mini NASDAQ 100 Futures, Continuous Contract #1\n            \"EUREX_FDAX1\",  # DAX Futures, Continuous Contract #1\n            \"CME_ES1\",  # E-mini S&P 500 Futures, Continuous Contract #1\n            \"EUREX_FSMI1\",  # SMI Futures, Continuous Contract #1\n            \"EUREX_FSTX1\",  # STOXX Europe 50 Index Futures, Continuous Contract #1\n            \"LIFFE_FCE1\",  # CAC40 Index Futures, Continuous Contract #1\n            \"LIFFE_Z1\",  # FTSE 100 Index Futures, Continuous Contract #1\n            \"SGX_NK1\",  # SGX Nikkei 225 Index Futures, Continuous Contract #1\n            \"CME_MD1\",  # E-mini S&P MidCap 400 Futures\n            \"CME_TY1\",  # 10 Yr Note Futures, Continuous Contract #1\n            \"CME_FV1\",  # 5 Yr Note Futures, Continuous Contract #1\n            \"CME_TU1\",  # 2 Yr Note Futures, Continuous Contract #1\n            \"ASX_XT1\",  # 10 Year Commonwealth Treasury Bond Futures, Continuous Contract #1   # 'Settlement price' instead of 'settle' on quandl.\n            \"ASX_YT1\",  # 3 Year Commonwealth Treasury Bond Futures, Continuous Contract #1    # 'Settlement price' instead of 'settle' on quandl.\n            \"EUREX_FGBL1\",  # Euro-Bund (10Y) Futures, Continuous Contract #1\n            \"EUREX_FBTP1\",  # Long-Term Euro-BTP Futures, Continuous Contract #1\n            \"EUREX_FGBM1\",  # Euro-Bobl Futures, Continuous Contract #1\n            \"EUREX_FGBS1\",  # Euro-Schatz Futures, Continuous Contract #1\n            \"SGX_JB1\",  # SGX 10-Year Mini Japanese Government Bond Futures\n            \"LIFFE_R1\"  # Long Gilt Futures, Continuous Contract #1\n            \"MX_CGB1\",  # Ten-Year Government of Canada Bond Futures, Continuous Contract #1    # 'Settlement price' instead of 'settle' on quandl.\n        ]\n\n        self.period = 12 * 21\n        self.SetWarmUp(self.period, Resolution.Daily)\n\n        self.targeted_volatility = 0.10\n        self.vol_target_period = 60\n        self.leverage_cap = 4\n\n        # Daily rolled data.\n        self.data = {}\n\n        for symbol in self.symbols:\n            data = None\n\n            # Back adjusted and spliced data import.\n            data = self.AddData(QuantpediaFutures, symbol, Resolution.Daily)\n\n            data.SetFeeModel(CustomFeeModel())\n            data.SetLeverage(20)\n\n            self.data[symbol] = RollingWindow[float](self.period)\n\n        self.recent_month = -1\n\n    def OnData(self, data):\n        # Store daily data.\n        for symbol in self.symbols:\n            if symbol in data and data[symbol]:\n                price = data[symbol].Value\n                self.data[symbol].Add(price)\n\n        if self.recent_month == self.Time.month:\n            return\n        self.recent_month = self.Time.month\n\n        # Performance and volatility data.\n        performance_volatility = {}\n        daily_returns = {}\n\n        for symbol in self.symbols:\n            if self.data[symbol].IsReady:\n                if (\n                    self.Securities[symbol].GetLastData()\n                    and (\n                        self.Time.date()\n                        - self.Securities[symbol].GetLastData().Time.date()\n                    ).days\n                    < 5\n                ):\n                    back_adjusted_prices = np.array([x for x in self.data[symbol]])\n                    performance = back_adjusted_prices[0] / back_adjusted_prices[-1] - 1\n                    daily_rets = (\n                        back_adjusted_prices[:-1] / back_adjusted_prices[1:] - 1\n                    )\n\n                    back_adjusted_prices = back_adjusted_prices[\n                        : self.vol_target_period\n                    ]\n                    daily_rets = (\n                        back_adjusted_prices[:-1] / back_adjusted_prices[1:] - 1\n                    )\n                    volatility_3M = np.std(daily_rets) * sqrt(252)\n                    daily_returns[symbol] = daily_rets[::-1][: self.vol_target_period]\n\n                    performance_volatility[symbol] = (performance, volatility_3M)\n\n        if len(performance_volatility) == 0:\n            return\n\n        # Performance sorting.\n        long = [x[0] for x in performance_volatility.items() if x[1][0] > 0]\n        short = [x[0] for x in performance_volatility.items() if x[1][0] < 0]\n\n        weight_by_symbol = {}\n\n        # Volatility weighting long and short leg separately.\n        ls_leverage = []  # long and short leverage\n\n        for sym_i, symbols in enumerate([long, short]):\n            total_volatility = sum([1 / performance_volatility[x][1] for x in symbols])\n\n            # Inverse volatility weighting.\n            weights = np.array(\n                [(1 / performance_volatility[x][1]) / total_volatility for x in symbols]\n            )\n            weights_sum = sum(weights)\n            weights = weights / weights_sum\n\n            df = pd.DataFrame()\n            i = 0\n            for symbol in symbols:\n                df[str(symbol)] = [x for x in daily_returns[symbol]]\n                weight_by_symbol[symbol] = weights[i] if sym_i == 0 else -weights[i]\n                i += 1\n\n            # volatility targeting\n            portfolio_vol = np.sqrt(\n                np.dot(weights.T, np.dot(df.cov() * 252, weights.T))\n            )\n            leverage = self.targeted_volatility / portfolio_vol\n            leverage = min(self.leverage_cap, leverage)  # cap max leverage\n            ls_leverage.append(leverage)\n\n        # Trade execution.\n        invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]\n        for symbol in invested:\n            if symbol not in long + short:\n                self.Liquidate(symbol)\n\n        for symbol, w in weight_by_symbol.items():\n            if w >= 0:\n                self.SetHoldings(symbol, w * ls_leverage[0])\n                # self.SetHoldings(symbol, w)\n            else:\n                self.SetHoldings(symbol, w * ls_leverage[1])\n                # self.SetHoldings(symbol, w)\n\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\";\")\n\n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data[\"back_adjusted\"] = float(split[1])\n        data[\"spliced\"] = float(split[2])\n        data.Value = float(split[1])\n\n        return data\n\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n"
  },
  {
    "path": "static/strategies/trading-wti-brent-spread.py",
    "content": "#region imports\nfrom AlgorithmImports import *\n#endregion\n# https://quantpedia.com/strategies/trading-wti-brent-spread/\n#\n# A 20-day moving average of WTI/Brent spread is calculated each day. If the current spread value is above SMA 20 then we enter a short position\n# in the spread on close (betting that the spread will decrease to the fair value represented by SMA 20). The trade is closed at the close of the\n# trading day when the spread crosses below fair value. If the current spread value is below SMA 20 then we enter a long position betting that \n# the spread will increase and the trade is closed at the close of the trading day when the spread crosses above fair value.\n\nclass WTIBRENTSpread(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n        \n        self.symbols = [\n            \"ICE_WT1\",  # WTI Crude Futures, Continuous Contract\n            \"ICE_B1\"    # Brent Crude Oil Futures, Continuous Contract\n        ]\n\n        self.spread = RollingWindow[float](20)\n        \n        for symbol in self.symbols:\n            data = self.AddData(QuantpediaFutures, symbol, Resolution.Daily)\n            data.SetLeverage(5)\n            data.SetFeeModel(CustomFeeModel())\n        \n    def OnData(self, data):\n        symbol1 = self.Symbol(self.symbols[0])\n        symbol2 = self.Symbol(self.symbols[1])\n        \n        if symbol1 in data.Keys and symbol2 in data.Keys and data[symbol1] and data[symbol2]:\n            price1 = data[symbol1].Price\n            price2 = data[symbol2].Price\n            \n            if price1 != 0 and price2 != 0:\n                spread = price1 - price2\n                self.spread.Add(spread)\n        \n        # MA calculation.\n        if self.spread.IsReady:\n            if (self.Time.date() - self.Securities[symbol1].GetLastData().Time.date()).days < 5 and (self.Time.date() - self.Securities[symbol2].GetLastData().Time.date()).days < 5:\n                spreads = [x for x in self.spread]\n                spread_ma20 = sum(spreads) / len(spreads)\n                \n                current_spread = spreads[0]\n                \n                if current_spread > spread_ma20:\n                    self.SetHoldings(symbol1, -1)\n                    self.SetHoldings(symbol2, 1)\n                elif current_spread < spread_ma20:\n                    self.SetHoldings(symbol1, 1)\n                    self.SetHoldings(symbol2, -1)\n            else:\n                self.Liquidate()\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n        split = line.split(';')\n        \n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data['back_adjusted'] = float(split[1])\n        data['spliced'] = float(split[2])\n        data.Value = float(split[1])\n\n        return data\n        \n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/trend-following-effect-in-stocks.py",
    "content": "# https://quantpedia.com/strategies/trend-following-effect-in-stocks/\n#\n# The investment universe consists of US-listed companies. A minimum stock price filter is used to avoid penny stocks, and a minimum\n# daily liquidity filter is used to avoid stocks that are not liquid enough. The entry signal occurs if today’s close is greater than\n# or equal to the highest close during the stock’s entire history. A 10-period average true range trailing stop is used as an exit \n# signal. The investor holds all stocks which satisfy entry criterion and are not stopped out. The portfolio is equally weighted and\n# rebalanced daily. Transaction costs of 0.5% round-turn are deducted from each trade to account for estimated commission and slippage.\n#\n# QC implementation:\n#   - Universe consists of top 100 liquid US stocks. \n\nimport numpy as np\nfrom AlgorithmImports import *\n\nclass TrendFollowingStocks(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2010, 1, 1)\n        self.SetCash(100000)\n\n        self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x)))\n        \n        self.course_count = 100\n        self.long = []\n        \n        self.max_close = {}\n        self.atr = {}\n        \n        self.sl_order = {}\n        self.sl_price = {}\n        \n        self.selection = []\n        self.period = 10*12*21\n        \n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction)\n    \n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            \n            symbol = security.Symbol\n            if symbol not in self.atr:\n                self.atr[symbol] = self.ATR(symbol, 10, Resolution.Daily)\n                \n            if symbol not in self.max_close:\n                hist = self.History([self.Symbol(symbol)], self.period, Resolution.Daily)\n                if 'close' in hist.columns:\n                    closes = hist['close']\n                    self.max_close[symbol] = max(closes)\n            \n    def CoarseSelectionFunction(self, coarse):\n        if self.IsWarmingUp: return\n    \n        selected = sorted([x for x in coarse if x.HasFundamentalData and x.Price > 5],\n            key=lambda x: x.DollarVolume, reverse=True)\n        \n        self.selection = [x.Symbol for x in selected[:self.course_count]]\n        \n        return self.selection\n\n    def OnData(self, data):\n        if self.IsWarmingUp:\n            return\n\n        for symbol in self.selection:\n            if symbol in data.Bars:\n                price = data[symbol].Value\n            \n                if symbol not in self.max_close: continue\n            \n                if price >= self.max_close[symbol]:\n                    self.max_close[symbol] = price\n                    self.long.append(symbol)\n\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        count = len(self.long) + len(stocks_invested)\n        if count == 0: return\n    \n        # Update stoploss orders\n        for symbol in stocks_invested:\n            if not self.Securities[symbol].IsTradable:\n                self.Liquidate(symbol)\n                \n            if self.atr[symbol].Current.Value == 0: continue\n            \n            # Move SL\n            if symbol not in self.sl_price: continue\n            \n            self.SetHoldings(symbol, 1 / count)\n            \n            new_sl = self.Securities[symbol].Price - self.atr[symbol].Current.Value\n            if new_sl > self.sl_price[symbol]:\n                update_order_fields = UpdateOrderFields()\n                update_order_fields.StopPrice = new_sl      # Update SL price\n                \n                quantity = self.CalculateOrderQuantity(symbol, (1 / count))\n                update_order_fields.Quantity = quantity     # Update SL quantity\n\n                self.sl_price[symbol] = new_sl\n                self.sl_order[symbol].Update(update_order_fields)\n                # self.Log('SL MOVED on ' + str(symbol) + ' to: ' + str(new_sl))\n\n        # Open new trades\n        for symbol in self.long:\n            if not self.Portfolio[symbol].Invested and self.atr[symbol].Current.Value != 0:\n                price = data[symbol].Value\n                if self.Securities[symbol].IsTradable:\n                    unit_size = self.CalculateOrderQuantity(symbol, (1 / count))\n                    \n                    self.MarketOrder(symbol, unit_size)\n                    \n                    sl_price = price - self.atr[symbol].Current.Value\n                    self.sl_price[symbol] = sl_price\n                    if unit_size != 0:\n                        self.sl_order[symbol] = self.StopMarketOrder(symbol, -unit_size, sl_price, 'SL')\n                    # self.Log('SL SET on ' + str(symbol) + ' to: ' + str(sl_price))\n\n        self.long.clear()\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/turn-of-the-month-in-equity-indexes.py",
    "content": "# https://quantpedia.com/strategies/turn-of-the-month-in-equity-indexes/\n#\n# Buy SPY ETF 1 day (some papers say 4 days) before the end of the month and sell the 3rd trading day of the new month at the close.\n\nfrom AlgorithmImports import *\n\nclass TurnoftheMonthinEquityIndexes(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(1998, 1, 1)\n        self.SetCash(100000)\n        \n        self.symbol = self.AddEquity(\"SPY\", Resolution.Daily).Symbol\n        \n        self.sell_flag = False\n        self.days = 0\n        \n        self.Schedule.On(self.DateRules.MonthStart(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Rebalance)\n        self.Schedule.On(self.DateRules.MonthEnd(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Purchase)\n    \n    def Purchase(self):\n        self.SetHoldings(self.symbol, 1)\n    \n    def Rebalance(self):\n        self.sell_flag = True\n        \n    def OnData(self, data):\n        if self.sell_flag:\n            self.days += 1\n            if self.days == 3:\n                self.Liquidate(self.symbol)\n                self.sell_flag = False\n                self.days = 0"
  },
  {
    "path": "static/strategies/value-and-momentum-factors-across-asset-classes.py",
    "content": "\"\"\"\ndata_tools.py\n\"\"\"\n\n# Bond yields\nclass QuandlAAAYield(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = \"BAMLC0A1CAAAEY\"\n\n\nclass QuandlHighYield(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = \"BAMLH0A0HYM2EY\"\n\n\n# Quantpedia bond yield data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaBondYield(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/bond_yield/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaBondYield()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\",\")\n\n        data.Time = datetime.strptime(split[0], \"%Y-%m-%d\") + timedelta(days=1)\n        data[\"yield\"] = float(split[1])\n        data.Value = float(split[1])\n\n        return data\n\n\n# Country PE data\n# NOTE: IMPORTANT: Data order must be ascending (date-wise)\nfrom dateutil.relativedelta import relativedelta\n\n\nclass CountryPE(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/economic/country_pe.csv\",\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = CountryPE()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\";\")\n\n        data.Time = datetime.strptime(split[0], \"%Y\") + relativedelta(years=1)\n        self.symbols = [\n            \"Argentina\",\n            \"Australia\",\n            \"Austria\",\n            \"Belgium\",\n            \"Brazil\",\n            \"Canada\",\n            \"Chile\",\n            \"China\",\n            \"Egypt\",\n            \"France\",\n            \"Germany\",\n            \"Hong Kong\",\n            \"India\",\n            \"Indonesia\",\n            \"Ireland\",\n            \"Israel\",\n            \"Italy\",\n            \"Japan\",\n            \"Malaysia\",\n            \"Mexico\",\n            \"Netherlands\",\n            \"New Zealand\",\n            \"Norway\",\n            \"Philippines\",\n            \"Poland\",\n            \"Russia\",\n            \"Saudi Arabia\",\n            \"Singapore\",\n            \"South Africa\",\n            \"South Korea\",\n            \"Spain\",\n            \"Sweden\",\n            \"Switzerland\",\n            \"Taiwan\",\n            \"Thailand\",\n            \"Turkey\",\n            \"United Kingdom\",\n            \"United States\",\n        ]\n        index = 1\n        for symbol in self.symbols:\n            data[symbol] = float(split[index])\n            index += 1\n\n        data.Value = float(split[1])\n        return data\n\n\n# Quandl \"value\" data\nclass QuandlValue(PythonQuandl):\n    def __init__(self):\n        self.ValueColumnName = \"Value\"\n\n\n# Quantpedia PE ratio data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaPERatio(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/economic/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaPERatio()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\";\")\n\n        data.Time = datetime.strptime(split[0], \"%Y-%m-%d\") + timedelta(days=1)\n        data[\"pe_ratio\"] = float(split[1])\n        data.Value = float(split[1])\n\n        return data\n\n\n# Quantpedia bond yield data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaBondYield(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/bond_yield/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaBondYield()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\",\")\n\n        data.Time = datetime.strptime(split[0], \"%Y-%m-%d\") + timedelta(days=1)\n        data[\"yield\"] = float(split[1])\n        data.Value = float(split[1])\n\n        return data\n\n\n# Quantpedia data.\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\nclass QuantpediaFutures(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\n            \"data.quantpedia.com/backtesting_data/futures/{0}.csv\".format(\n                config.Symbol.Value\n            ),\n            SubscriptionTransportMedium.RemoteFile,\n            FileFormat.Csv,\n        )\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = QuantpediaFutures()\n        data.Symbol = config.Symbol\n\n        if not line[0].isdigit():\n            return None\n        split = line.split(\";\")\n\n        data.Time = datetime.strptime(split[0], \"%d.%m.%Y\") + timedelta(days=1)\n        data[\"back_adjusted\"] = float(split[1])\n        data[\"spliced\"] = float(split[2])\n        data.Value = float(split[1])\n\n        return data\n\n\n\"\"\"\nmain.py\n\"\"\"\n\n# https://quantpedia.com/strategies/value-and-momentum-factors-across-asset-classes/\n#\n# Create an investment universe containing investable asset classes (could be US large-cap, mid-cap stocks, US REITS, UK, Japan, Emerging market stocks, US treasuries, US Investment grade bonds,\n# US high yield bonds, Germany bonds, Japan bonds, US cash) and find a good tracking vehicle for each asset class (best vehicles are ETFs or index funds). Momentum ranking is done on price series.\n# Valuation ranking is done on adjusted yield measure for each asset class. E/P (Earning/Price) measure is used for stocks, and YTM (Yield-to-maturity) is used for bonds. US, Japan, and Germany\n# treasury yield are adjusted by -1%, US investment-grade bonds are adjusted by -2%, US High yield bonds are adjusted by -6%, emerging markets equities are adjusted by -1%, and US REITs are\n# adjusted by -2% to get unbiased structural yields for each asset class. Rank each asset class by 12-month momentum, 1-month momentum, and by valuation and weight all three strategies (25% weight\n# to 12m momentum, 25% weight to 1-month momentum, 50% weight to value strategy). Go long top quartile portfolio and go short bottom quartile portfolio.\n#\n# QC implementation changes:\n#   - Country PB data ends in 2019. Last known value is used for further years calculations for the sake of backtest.\n\nimport data_tools\n\n\nclass ValueandMomentumFactorsacrossAssetClasses(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2013, 1, 1)\n        self.SetCash(100000)\n\n        # investable asset, yield symbol, yield data access function, yield adjustment, reverse flag(PE -> EP)\n        self.assets = [\n            (\n                \"SPY\",\n                \"MULTPL/SP500_EARNINGS_YIELD_MONTH\",\n                data_tools.QuandlValue,\n                0,\n                True,\n            ),  # US large-cap\n            (\n                \"MDY\",\n                \"MID_CAP_PE\",\n                data_tools.QuantpediaPERatio,\n                0,\n                True,\n            ),  # US mid-cap stocks\n            (\n                \"IYR\",\n                \"REITS_DIVIDEND_YIELD\",\n                data_tools.QuantpediaPERatio,\n                -2,\n                False,\n            ),  # US REITS - same csv data format as PERatio files\n            (\"EWU\", \"United Kingdom\", None, 0, True),  # UK\n            (\"EWJ\", \"Japan\", None, 0, True),  # Japan\n            (\n                \"EEM\",\n                \"EMERGING_MARKET_PE\",\n                data_tools.QuantpediaPERatio,\n                -1,\n                True,\n            ),  # Emerging market stocks\n            (\n                \"LQD\",\n                \"ML/AAAEY\",\n                data_tools.QuandlAAAYield,\n                -2,\n                False,\n            ),  # US Investment grade bonds\n            (\n                \"HYG\",\n                \"ML/USTRI\",\n                data_tools.QuandlHighYield,\n                -6,\n                False,\n            ),  # US high yield bonds\n            (\n                \"CME_TY1\",\n                \"US10YT\",\n                data_tools.QuantpediaBondYield,\n                -1,\n                False,\n            ),  # US bonds\n            (\n                \"EUREX_FGBL1\",\n                \"DE10YT\",\n                data_tools.QuantpediaBondYield,\n                -1,\n                False,\n            ),  # Germany bonds\n            (\n                \"SGX_JB1\",\n                \"JP10YT\",\n                data_tools.QuantpediaBondYield,\n                -1,\n                False,\n            ),  # Japan bonds\n            (\n                \"BIL\",\n                \"OECD/KEI_IRSTCI01_USA_ST_M\",\n                data_tools.QuandlValue,\n                0,\n                False,\n            ),  # US cash\n        ]\n\n        # country pe data\n        self.country_pe_data = self.AddData(data_tools.CountryPE, \"CountryData\").Symbol\n\n        self.data = {}\n        self.period = 12 * 21\n        self.SetWarmUp(self.period)\n\n        for symbol, yield_symbol, yield_access, _, _ in self.assets:\n            # investable asset\n            if yield_access == data_tools.QuantpediaBondYield:\n                data = self.AddData(\n                    data_tools.QuantpediaFutures, symbol, Resolution.Daily\n                )\n            else:\n                data = self.AddEquity(symbol, Resolution.Daily)\n\n            # yield\n            if yield_access != None:\n                self.AddData(yield_access, yield_symbol, Resolution.Daily)\n\n            self.data[symbol] = RollingWindow[float](self.period)\n\n            data.SetFeeModel(CustomFeeModel(self))\n            data.SetLeverage(5)\n\n        self.recent_month = -1\n\n    def OnData(self, data):\n        if self.IsWarmingUp:\n            return\n\n        # store investable asset price data\n        for symbol, yield_symbol, _, _, _ in self.assets:\n            symbol_obj = self.Symbol(symbol)\n            if symbol_obj in data and data[symbol_obj]:\n                self.data[symbol].Add(data[symbol_obj].Value)\n\n        if self.Time.month == self.recent_month:\n            return\n        self.recent_month = self.Time.month\n\n        performance_1M = {}\n        performance_12M = {}\n        valuation = {}\n\n        # performance and valuation calculation\n        if (\n            self.Securities[self.country_pe_data].GetLastData()\n            and (\n                self.Time.date()\n                - self.Securities[self.country_pe_data].GetLastData().Time.date()\n            ).days\n            <= 365\n        ):\n            for (\n                symbol,\n                yield_symbol,\n                yield_access,\n                bond_adjustment,\n                reverse_flag,\n            ) in self.assets:\n                if (\n                    self.Securities[symbol].GetLastData()\n                    and (\n                        self.Time.date()\n                        - self.Securities[symbol].GetLastData().Time.date()\n                    ).days\n                    < 3\n                ):\n                    if self.data[symbol].IsReady:\n                        closes = [x for x in self.data[symbol]]\n                        performance_1M[symbol] = closes[0] / closes[21] - 1\n                        performance_12M[symbol] = (\n                            closes[0] / closes[len(closes) - 1] - 1\n                        )\n\n                        if yield_access == None:\n                            country_pb_data = self.Securities[\n                                \"CountryData\"\n                            ].GetLastData()\n                            if country_pb_data:\n                                pe = country_pb_data[yield_symbol]\n                                yield_value = pe\n                        else:\n                            yield_value = self.Securities[\n                                self.Symbol(yield_symbol)\n                            ].Price\n\n                        # reverse if needed, EP->PE\n                        if reverse_flag:\n                            yield_value = 1 / yield_value\n\n                        if yield_value != 0:\n                            valuation[symbol] = yield_value + bond_adjustment\n\n        long = []\n        short = []\n\n        if len(valuation) != 0:\n            # sort assets by metrics\n            sorted_by_p1 = sorted(performance_1M.items(), key=lambda x: x[1])\n            sorted_by_p12 = sorted(performance_12M.items(), key=lambda x: x[1])\n            sorted_by_value = sorted(valuation.items(), key=lambda x: x[1])\n\n            # rank assets\n            score = {}\n            for i, (symbol, _) in enumerate(sorted_by_p1):\n                score[symbol] = i * 0.25\n            for i, (symbol, _) in enumerate(sorted_by_p12):\n                score[symbol] += i * 0.25\n            for i, (symbol, _) in enumerate(sorted_by_value):\n                score[symbol] += i * 0.5\n\n            # sort by rank\n            sorted_by_rank = sorted(score, key=lambda x: score[x], reverse=True)\n            quartile = int(len(sorted_by_rank) / 4)\n            long = sorted_by_rank[:quartile]\n            short = sorted_by_rank[-quartile:]\n\n        # trade execution\n        invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]\n        for symbol in invested:\n            if symbol not in long + short:\n                self.Liquidate(symbol)\n\n        long_count = len(long)\n        short_count = len(short)\n\n        for symbol in long:\n            self.SetHoldings(symbol, 1 / long_count)\n        for symbol in short:\n            self.SetHoldings(symbol, -1 / short_count)\n\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))\n"
  },
  {
    "path": "static/strategies/value-book-to-market-factor.py",
    "content": "# https://quantpedia.com/strategies/value-book-to-market-factor/\n#\n# The investment universe contains all NYSE, AMEX, and NASDAQ stocks. To represent “value” investing, HML portfolio goes long high book-to-price stocks and short,\n# low book-to-price stocks. In this strategy, we show the results for regular HML which is simply the average of the portfolio returns of HML small (which goes long \n# cheap and short expensive only among small stocks) and HML large (which goes long cheap and short expensive only among large caps). The portfolio is equal-weighted\n# and rebalanced monthly.\n#\n# QC implementation changes:\n#   - Instead of all listed stock, we select top 3000 stocks by market cap from QC stock universe.\n    \nfrom AlgorithmImports import *\n\nclass Value(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2000, 1, 1)\n        self.SetCash(100000)\n\n        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol\n        \n        self.coarse_count = 3000\n        \n        self.long = []\n        self.short = []\n        \n        self.month = 12\n        self.selection_flag = False\n        self.UniverseSettings.Resolution = Resolution.Daily\n        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)\n        \n        self.Schedule.On(self.DateRules.MonthEnd(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Selection)\n\n    def OnSecuritiesChanged(self, changes):\n        for security in changes.AddedSecurities:\n            security.SetFeeModel(CustomFeeModel())\n            security.SetLeverage(5)\n\n    def CoarseSelectionFunction(self, coarse):\n        if not self.selection_flag:\n            return Universe.Unchanged\n        \n        selected = [x.Symbol for x in coarse if x.HasFundamentalData and x.Market == 'usa']\n        return selected\n    \n    def FineSelectionFunction(self, fine):\n        sorted_by_market_cap = sorted([x for x in fine if x.ValuationRatios.PBRatio != 0 and \\\n                            ((x.SecurityReference.ExchangeId == \"NYS\") or (x.SecurityReference.ExchangeId == \"NAS\") or (x.SecurityReference.ExchangeId == \"ASE\"))],\n                            key = lambda x:x.MarketCap, reverse=True)\n                            \n        top_by_market_cap = [x for x in sorted_by_market_cap[:self.coarse_count]]\n\n        sorted_by_pb = sorted(top_by_market_cap, key = lambda x:(x.ValuationRatios.PBRatio), reverse=False)\n        quintile = int(len(sorted_by_pb) / 5)\n        self.long = [i.Symbol for i in sorted_by_pb[:quintile]]\n        self.short = [i.Symbol for i in sorted_by_pb[-quintile:]]\n        \n        return self.long + self.short\n    \n    def OnData(self, data):\n        if not self.selection_flag:\n            return\n        self.selection_flag = False\n        \n        # Trade execution.\n        stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in stocks_invested:\n            if symbol not in self.long + self.short:\n                self.Liquidate(symbol)\n        \n        # Leveraged portfolio - 100% long, 100% short. \n        for symbol in self.long:\n            self.SetHoldings(symbol, 1 / len(self.long))\n\n        for symbol in self.short:\n            self.SetHoldings(symbol, -1 / len(self.short))\n\n        self.long.clear()\n        self.short.clear()\n    \n    def Selection(self):\n        if self.month == 12:\n            self.selection_flag = True\n        \n        self.month += 1\n        if self.month > 12:\n            self.month = 1\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/value-factor-effect-within-countries.py",
    "content": "# https://quantpedia.com/strategies/value-factor-effect-within-countries/\n#\n# The investment universe consists of 32 countries with easily accessible equity markets (via ETFs, for example). At the end of every year, \n# the investor calculates Shiller’s “CAPE” Cyclically Adjusted PE) ratio, for each country in his investment universe. CAPE is the ratio of \n# the real price of the equity market (adjusted for inflation) to the 10-year average of the country’s equity index (again adjusted for inflation). \n# The whole methodology is explained well on Shiller’s home page (http://www.econ.yale.edu/~shiller/data.htm) or\n# http://turnkeyanalyst.com/2011/10/the-shiller-pe-ratio/). The investor then invests in the cheapest 33% of countries from his sample if those \n# countries have a CAPE below 15. The portfolio is equally weighted (the investor holds 0% cash instead of countries with a CAPE higher than 15)\n# and rebalanced yearly.\n\n#region imports\nfrom AlgorithmImports import *\n#endregion\n\nclass ValueFactorCAPEEffectwithinCountries(QCAlgorithm):\n\n    def Initialize(self):\n        self.SetStartDate(2008, 1, 1)  \n        self.SetCash(100000)\n\n        self.symbols = {\n            \"Australia\"     : \"EWA\",  # iShares MSCI Australia Index ETF\n            \"Brazil\"        : \"EWZ\",  # iShares MSCI Brazil Index ETF\n            \"Canada\"        : \"EWC\",  # iShares MSCI Canada Index ETF\n            \"Switzerland\"   : \"EWL\",  # iShares MSCI Switzerland Index ETF\n            \"China\"         : \"FXI\",  # iShares China Large-Cap ETF\n            \"France\"        : \"EWQ\",  # iShares MSCI France Index ETF\n            \"Germany\"       : \"EWG\",  # iShares MSCI Germany ETF \n            \"Hong Kong\"     : \"EWH\",  # iShares MSCI Hong Kong Index ETF\n            \"Italy\"         : \"EWI\",  # iShares MSCI Italy Index ETF\n            \"Japan\"         : \"EWJ\",  # iShares MSCI Japan Index ETF\n            \"Korea\"         : \"EWY\",  # iShares MSCI South Korea ETF\n            \"Mexico\"        : \"EWW\",  # iShares MSCI Mexico Inv. Mt. Idx\n            \"Netherlands\"   : \"EWN\",  # iShares MSCI Netherlands Index ETF\n            \"South Africa\"  : \"EZA\",  # iShares MSCI South Africe Index ETF\n            \"Singapore\"     : \"EWS\",  # iShares MSCI Singapore Index ETF\n            \"Spain\"         : \"EWP\",  # iShares MSCI Spain Index ETF\n            \"Sweden\"        : \"EWD\",  # iShares MSCI Sweden Index ETF\n            \"Taiwan\"        : \"EWT\",  # iShares MSCI Taiwan Index ETF\n            \"UK\"            : \"EWU\",  # iShares MSCI United Kingdom Index ETF\n            \"USA\"           : \"SPY\",  # SPDR S&P 500 ETF\n            \n            \"Russia\"        : \"ERUS\",  # iShares MSCI Russia ETF\n            \"Israel\"        : \"EIS\",   # iShares MSCI Israel ETF\n            \"India\"         : \"INDA\",  # iShares MSCI India ETF\n            \"Poland\"        : \"EPOL\",  # iShares MSCI Poland ETF\n            \"Turkey\"        : \"TUR\"    # iShares MSCI Turkey ETF\n        }\n\n        for country, etf_symbol in self.symbols.items():\n            data = self.AddEquity(etf_symbol, Resolution.Daily)\n            data.SetFeeModel(CustomFeeModel())\n        \n        self.quantile:int = 3\n        self.max_missing_days:int = 31\n\n        # CAPE data import.\n        self.cape_data = self.AddData(CAPE, 'CAPE',  Resolution.Daily).Symbol\n            \n        self.recent_month:int = -1\n    \n    def OnData(self, data:Slice) -> None:\n        if self.Time.month == self.recent_month:\n            return\n        self.recent_month = self.Time.month\n\n        if self.recent_month != 12:\n            return\n        \n        price = {}\n        for country, etf_symbol in self.symbols.items():\n            if etf_symbol in data and data[etf_symbol]:\n                # cape data is still coming in\n                if self.Securities[self.cape_data].GetLastData() and (self.Time.date() - self.Securities[self.cape_data].GetLastData().Time.date()).days <= self.max_missing_days:\n                    country_cape = self.Securities['CAPE'].GetLastData().GetProperty(country)\n                    if country_cape < 15:\n                        price[etf_symbol] = data[etf_symbol].Value\n\n        long = []\n        \n        # Cape and price sorting.\n        if len(price) >= self.quantile:\n            sorted_by_price = sorted(price.items(), key = lambda x: x[1], reverse = True)\n            tercile = int(len(sorted_by_price) / self.quantile)\n            long = [x[0] for x in sorted_by_price[-tercile:]]\n        \n        # Trade execution.\n        invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n        for symbol in invested:\n            if symbol not in long:\n                self.Liquidate(symbol)\n        \n        for symbol in long:\n            if self.Securities[etf_symbol].Price != 0 and self.Securities[etf_symbol].IsTradable:\n                self.SetHoldings(symbol, 1 / len(long))\n\n# NOTE: IMPORTANT: Data order must be ascending (datewise)\n# Data source: https://indices.barclays/IM/21/en/indices/static/historic-cape.app\nclass CAPE(PythonData):\n    def GetSource(self, config, date, isLiveMode):\n        return SubscriptionDataSource(\"data.quantpedia.com/backtesting_data/economic/cape_by_country.csv\", SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)\n\n    def Reader(self, config, line, date, isLiveMode):\n        data = CAPE()\n        data.Symbol = config.Symbol\n        \n        if not line[0].isdigit(): return None\n        split = line.split(';')\n        \n        data.Time = datetime.strptime(split[0], \"%Y-%m-%d\") + timedelta(days=1)\n        \n        data['Australia'] = float(split[1])\n        data['Brazil'] = float(split[2])\n        data['Canada'] = float(split[3])\n        data['Switzerland'] = float(split[4])\n        data['China'] = float(split[5])\n        data['France'] = float(split[6])\n        data['Germany'] = float(split[7])\n        data['Hong Kong'] = float(split[8])\n        data['India'] = float(split[9])\n        data['Israel'] = float(split[10])\n        data['Italy'] = float(split[11])\n        data['Japan'] = float(split[12])\n        data['Korea'] = float(split[13])\n        data['Mexico'] = float(split[14])\n        data['Netherlands'] = float(split[15])\n        data['Poland'] = float(split[16])\n        data['Russia'] = float(split[17])\n        data['South Africa'] = float(split[18])\n        data['Singapore'] = float(split[19])\n        data['Spain'] = float(split[20])\n        data['Sweden'] = float(split[21])\n        data['Taiwan'] = float(split[22])\n        data['Turkey'] = float(split[23])\n        data['UK'] = float(split[24])\n        data['USA'] = float(split[25])\n        \n        data.Value = float(split[1])\n\n        return data\n\n# Custom fee model.\nclass CustomFeeModel(FeeModel):\n    def GetOrderFee(self, parameters):\n        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005\n        return OrderFee(CashAmount(fee, \"USD\"))"
  },
  {
    "path": "static/strategies/volatility-risk-premium-effect.py",
    "content": "# https://quantpedia.com/strategies/volatility-risk-premium-effect/\n#\n# Each month, at-the-money straddle, with one month until maturity, is sold at the bid price with a 5% option premium, and an offsetting 15%\n# out-of-the-money puts are bought (at the ask price) as insurance against a market crash. The remaining cash and received option premium are\n# invested in the index. The strategy is rebalanced monthly.\n\nfrom AlgorithmImports import *\n\n\nclass VolatilityRiskPremiumEffect(QCAlgorithm):\n    def Initialize(self):\n        self.SetStartDate(2010, 1, 1)\n        self.SetCash(100000)\n\n        data = self.AddEquity(\"SPY\", Resolution.Minute)\n        data.SetLeverage(5)\n        self.symbol = data.Symbol\n\n        option = self.AddOption(\"SPY\", Resolution.Minute)\n        option.SetFilter(-20, 20, 25, 35)\n\n        self.last_day = -1\n\n    def OnData(self, slice):\n        # Check once a day.\n        if self.Time.day == self.last_day:\n            return\n        self.last_day = self.Time.day\n\n        for i in slice.OptionChains:\n            chains = i.Value\n\n            if not self.Portfolio.Invested:\n                # divide option chains into call and put options\n                calls = list(filter(lambda x: x.Right == OptionRight.Call, chains))\n                puts = list(filter(lambda x: x.Right == OptionRight.Put, chains))\n\n                # if lists are empty return\n                if not calls or not puts:\n                    return\n\n                underlying_price = self.Securities[self.symbol].Price\n                expiries = [i.Expiry for i in puts]\n\n                # determine expiration date nearly one month\n                expiry = min(\n                    expiries, key=lambda x: abs((x.date() - self.Time.date()).days - 30)\n                )\n                strikes = [i.Strike for i in puts]\n\n                # determine at-the-money strike\n                strike = min(strikes, key=lambda x: abs(x - underlying_price))\n\n                # determine 15% out-of-the-money strike\n                otm_strike = min(\n                    strikes, key=lambda x: abs(x - float(0.85) * underlying_price)\n                )\n\n                atm_call = [\n                    i for i in calls if i.Expiry == expiry and i.Strike == strike\n                ]\n                atm_put = [i for i in puts if i.Expiry == expiry and i.Strike == strike]\n                otm_put = [\n                    i for i in puts if i.Expiry == expiry and i.Strike == otm_strike\n                ]\n\n                if atm_call and atm_put and otm_put:\n                    options_q = int(\n                        self.Portfolio.MarginRemaining / (underlying_price * 100)\n                    )\n\n                    # Set max leverage.\n                    self.Securities[atm_call[0].Symbol].MarginModel = BuyingPowerModel(\n                        5\n                    )\n                    self.Securities[atm_put[0].Symbol].MarginModel = BuyingPowerModel(5)\n                    self.Securities[otm_put[0].Symbol].MarginModel = BuyingPowerModel(5)\n\n                    # sell at-the-money straddle\n                    self.Sell(atm_call[0].Symbol, options_q)\n                    self.Sell(atm_put[0].Symbol, options_q)\n\n                    # buy 15% out-of-the-money put\n                    self.Buy(otm_put[0].Symbol, options_q)\n\n                    # buy index.\n                    self.SetHoldings(self.symbol, 1)\n\n            invested = [x.Key for x in self.Portfolio if x.Value.Invested]\n            if len(invested) == 1:\n                self.Liquidate(self.symbol)\n"
  }
]