pyquants 1.2.9
PyQuants is a portable Python time series backtesting toolkit.
License: mit
Requires Python: >=3.6

![logo](https://github.com/YannisYuan/pyquants/blob/master/logo.png?raw=true)
# PyQuants: portable Python time series backtesting toolkit
[![Version](https://img.shields.io/badge/PyPi-v1.2.7-blue)](https://pypi.org/project/pyquants/)
[![Status](https://img.shields.io/badge/status-stable-brightgreen)](https://pypi.org/project/pyquants/)
[![License](https://img.shields.io/badge/license-MIT-brightgreen)](https://github.com/YannisYuan/pyquants/blob/master/LICENSE.md)
[![Build](https://travis-ci.org/YannisYuan/pyquants.svg?branch=master)](https://travis-ci.org/github/YannisYuan/pyquants)
[![Gitter](https://badges.gitter.im/PyQuants/community.svg)](https://gitter.im/PyQuants/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)


`pyquants` is a Python library for financial time series processing and backtesting with a variety of plotting functions. 

## Dependencies

`pyquants` supports Python 3.6+.

`pyquants` is a high-level library and the installation of which requires `pandas`, `numpy`, `scipy`, `matplotlib`, `seaborn`, `statsmodels`, `scikit-learn`, `pmdarima`, `yfinance`, `empyrical`, `pyfolio`, and `tqdm`.

## Installation

Use the package manager [pip](https://pip.pypa.io/en/stable/) or folk from [GitHub](https://github.com/YannisYuan/pyquants/) to install `pyquants`. 
```bash
pip install pyquants
```

## Load data

Load sample daily financial data to start the work. 

```bash
import pyquants as pq
from pyquants.transform import *
FX = pq.load_fx()
print(FX["DMFX.PRC"].pipe(HT)) # load the head and tail of DMFX
```

## Processing and plotting

Plot the technical chart and cumulative returns of time series processed with various operators. 

```bash
# Technical charting
eurusd = FX["FX.PRC"]["2019-09":"2020-08"]["EUR"] # load EUR/USD data

eurusd.pipe(pq.plot_technical, # plot a technical chart
            style="line", # use "line" style since only "close" data is available
            benchmark=None, 
            sma=[10, 50], # use multiple windows for simple moving average
            bollinger_bands=False, # turn off Bollinger Bands 
            title="EUR/USD Chart",
            figsize=(16, 9))

aapl = yf.download("AAPL", # load ohlc data from yfinance
                   start="2019-09-01", end="2020-08-31", 
                   progress=False, auto_adjust=True)

aapl.pipe(pq.plot_technical, # plot a technical chart 
          style="candlestick", # use "candlestick" style and chart with ohlc data
          benchmark="SPY", # add a benchmark for comparison
          bollinger_bands=True, # turn on Bollinger Bands
          macd=True, # plot MACD in subpanel
          rsi=False, # turn off RSI 
          atr=True, # plot ATR in subpanel
          title="AAPL Chart", 
          figsize=(16, 9))
```

```bash
# Cumulative returns
dmfx_rtn = FX["DMFX.PRC"].pipe(RTN) # get the return series with RTN operator

(dmfx_rtn.pipe(EMA, 5) # apply EMA(5) to smooth the returns
         .pipe(NORM, 252, method="exponential") # apply NORM(252) to normalise returns
         .pipe(pq.plot_return, start="2000")) # plot the cumulative compound returns 

dmfx_rtn.pipe(pq.plot_acf_pacf) # plot the ACF and PACF of return series
dmfx_rtn.pipe(pq.plot_decompose) # plot the seasonal decomposition of return series
dmfx_rtn.pipe(pq.plot_dist, stat="density", standardise=False) # histogram and Q-Q plot

(aapl["Close"].pipe(RTN)
              .pipe(pq.plot_market_corr, # joint plot the correlation with benchmark 
                    name="AAPL", 
                    benchmark="SPY")) 
```

## Backtesting

Signals can be easily backtested with a variety of result summary plots. 

```bash
# Construct a simple signal
df_fx = (dmfx_rtn.sub(dmfx_rtn.shift(1).pipe(EMA, 10)) # returns less past 10D EMA
                 .pipe(NORM, 20) # normalise with monthly volatility
                 .pipe(np.sign) # take the sign only
                 .mul(-1) # trade the reversal
                 .pipe(XSDM)) # cross-sectional de-mean series

bt_fx = df_fx.pipe(pq.bt_fx, # backtest series and plot the 6-piece summary plot
                   benchmark=None, 
                   rf=0.0, # set the risk-free rate to 0
                   tc=3*10e-6, # set the transaction cost factor
                   vol_target=0.1, # activate the volatility scaler to cap estimated risk
                   figsize=(16, 9),  
                   output_returns=True) # output the return DataFrame for all assets

bt_rtn.pipe(pq.plot_rolling_vol, window=126) # plot 6M rolling volatility
bt_rtn.pipe(pq.plot_rolling_sharpe, window=126, rf=0) # plot 6M rolling Sharpe ratio
bt_rtn.pipe(pq.plot_monthly_return_heatmap) # plot monthly return heatmap of the signal
bt_rtn.pipe(pq.plot_annual_return) # plot annual return of each year
```
![backtest](https://github.com/YannisYuan/pyquants/blob/master/backtest.png?raw=true)

## Modelling and forecasting

Simple ETS and ARIMA models are wrapped in the module. Using the following functions automatically fill the correponding entries with the forecast for the next period's value. 

```bash
# Exponential smoothing
df_ets = aapl.Close.pipe(pq.ETS, expanding=True, damped=True, damping_slope=0.99)  
(aapl.Close.pipe(pd.merge, # merge two series
                 df_ets.shift(1).dropna(), # delay 1D to compare actual vs. predicted
                 left_index=True, 
                 right_index=True,
                 how="inner")
            .pipe(plot_series, title="AAPL Actual vs. ETS Forecast"))

# ARIMA
df_arima = aapl.Close.pipe(pq.ARIMA, expanding=True, seasonal=False)
(aapl.Close.pipe(pd.merge,  # merge two series
                 df_arima.shift(1).dropna(), # delay 1D to compare actual vs. predicted
                 left_index=True,
                 right_index=True,
                 how="inner")
            .pipe(plot_series, title="AAPL Actual vs. ARIMA Forecast"))

```

## References

`pyquants` references certain functions from `empyrical` and `pyfolio` to build an integrated quantitative analysis tool. 

## License

[MIT License](https://github.com/YannisYuan/pyquants/blob/master/LICENSE.md)