Giter VIP home page Giter VIP logo

quantstats's Introduction

Python version

PyPi version

PyPi status

PyPi downloads

CodeFactor

Star this repo

Follow me on twitter

QuantStats: Portfolio analytics for quants ==========================================

QuantStats Python library that performs portfolio profiling, allowing quants and portfolio managers to understand their performance better by providing them with in-depth analytics and risk metrics.

Changelog »

QuantStats is comprised of 3 main modules:

  1. quantstats.stats - for calculating various performance metrics, like Sharpe ratio, Win rate, Volatility, etc.
  2. quantstats.plots - for visualizing performance, drawdowns, rolling statistics, monthly returns, etc.
  3. quantstats.reports - for generating metrics reports, batch plotting, and creating tear sheets that can be saved as an HTML file.

Here's an example of a simple tear sheet analyzing a strategy:

Quick Start

%matplotlib inline
import quantstats as qs

# extend pandas functionality with metrics, etc.
qs.extend_pandas()

# fetch the daily returns for a stock
stock = qs.utils.download_returns('META')

# show sharpe ratio
qs.stats.sharpe(stock)

# or using extend_pandas() :)
stock.sharpe()

Output:

0.8135304438803402

Visualize stock performance

qs.plots.snapshot(stock, title='Facebook Performance', show=True)

# can also be called via:
# stock.plot_snapshot(title='Facebook Performance', show=True)

Output:

Snapshot plot

Creating a report

You can create 7 different report tearsheets:

  1. qs.reports.metrics(mode='basic|full", ...) - shows basic/full metrics
  2. qs.reports.plots(mode='basic|full", ...) - shows basic/full plots
  3. qs.reports.basic(...) - shows basic metrics and plots
  4. qs.reports.full(...) - shows full metrics and plots
  5. qs.reports.html(...) - generates a complete report as html

Let' create an html tearsheet

(benchmark can be a pandas Series or ticker)
qs.reports.html(stock, "SPY")

Output will generate something like this:

HTML tearsheet

(view original html file)

To view a complete list of available methods, run

[f for f in dir(qs.stats) if f[0] != '_']
['avg_loss',
 'avg_return',
 'avg_win',
 'best',
 'cagr',
 'calmar',
 'common_sense_ratio',
 'comp',
 'compare',
 'compsum',
 'conditional_value_at_risk',
 'consecutive_losses',
 'consecutive_wins',
 'cpc_index',
 'cvar',
 'drawdown_details',
 'expected_return',
 'expected_shortfall',
 'exposure',
 'gain_to_pain_ratio',
 'geometric_mean',
 'ghpr',
 'greeks',
 'implied_volatility',
 'information_ratio',
 'kelly_criterion',
 'kurtosis',
 'max_drawdown',
 'monthly_returns',
 'outlier_loss_ratio',
 'outlier_win_ratio',
 'outliers',
 'payoff_ratio',
 'profit_factor',
 'profit_ratio',
 'r2',
 'r_squared',
 'rar',
 'recovery_factor',
 'remove_outliers',
 'risk_of_ruin',
 'risk_return_ratio',
 'rolling_greeks',
 'ror',
 'sharpe',
 'skew',
 'sortino',
 'adjusted_sortino',
 'tail_ratio',
 'to_drawdown_series',
 'ulcer_index',
 'ulcer_performance_index',
 'upi',
 'utils',
 'value_at_risk',
 'var',
 'volatility',
 'win_loss_ratio',
 'win_rate',
 'worst']
[f for f in dir(qs.plots) if f[0] != '_']
['daily_returns',
 'distribution',
 'drawdown',
 'drawdowns_periods',
 'earnings',
 'histogram',
 'log_returns',
 'monthly_heatmap',
 'returns',
 'rolling_beta',
 'rolling_sharpe',
 'rolling_sortino',
 'rolling_volatility',
 'snapshot',
 'yearly_returns']

*** Full documenttion coming soon ***

In the meantime, you can get insights as to optional parameters for each method, by using Python's help method:

help(qs.stats.conditional_value_at_risk)
Help on function conditional_value_at_risk in module quantstats.stats:

conditional_value_at_risk(returns, sigma=1, confidence=0.99)
    calculats the conditional daily value-at-risk (aka expected shortfall)
    quantifies the amount of tail risk an investment

Installation

Install using pip:

$ pip install quantstats --upgrade --no-cache-dir

Install using conda:

$ conda install -c ranaroussi quantstats

Requirements

Questions?

This is a new library... If you find a bug, please open an issue in this repository.

If you'd like to contribute, a great place to look is the issues marked with help-wanted.

Known Issues

For some reason, I couldn't find a way to tell seaborn not to return the monthly returns heatmap when instructed to save - so even if you save the plot (by passing savefig={...}) it will still show the plot.

QuantStats is distributed under the Apache Software License. See the LICENSE.txt file in the release for details.

P.S.

Please drop me a note with any feedback you have.

Ran Aroussi

quantstats's People

Contributors

amirnajafi avatar bartstolarek avatar binary-signal avatar dependabot-preview[bot] avatar dependabot[bot] avatar djl0 avatar drusakov778 avatar duxiaoyao avatar gabrieljenik avatar galarosa avatar git-shogg avatar gmjohns avatar grizzlybearg avatar jatorna avatar jgopel avatar kartiksubbarao avatar lau-jay avatar manhinhang avatar ranaroussi avatar rmfish avatar s0ap avatar snowhit3 avatar taohu88 avatar tradingdominion avatar whisperes avatar yarimiz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

quantstats's Issues

CAGR

Hi, i use your module - thanks. i think the CAGR calculation is not correct. For example :

                        Strategie          BM
Cumulative Return          81.23%      79.44%
CAGR%                      -1.38%      -1.52%

to check this quick, i used:

https://www.investopedia.com/calculator/cagr.aspx

Beginning Value:
100
Ending Value:
181.23
Number of Periods:
14

Result: Compound Annual Growth Rate:4.34%

greets

The columns of "strategy" and "benchmark" are upside down.

Hi Ran. Thanks for the library :)

The issue I'm reporting is that the columns in the tearsheet are not correct and need to be swapped.
For instance, in the following image, Cumulative Return and Time in Market is evidence that values don't correspond to the column.

Screenshot from 2019-12-12 17-35-30

Cheers!

Error at package install - conda

Hi,

I'm trying to install QuantStats for Anaconda using this command:
"conda install -c ranaroussi quantstats"

I am facing the following error:
"_The following NEW packages will be INSTALLED:

multitasking ranaroussi/noarch::multitasking-0.0.9-py_0
quantstats ranaroussi/noarch::quantstats-0.0.25-py_0
tabulate pkgs/main/win-64::tabulate-0.8.3-py37_0
yfinance ranaroussi/noarch::yfinance-0.1.54-py_0

Proceed ([y]/n)? y

Downloading and Extracting Packages
yfinance-0.1.54 | 735 KB | ############################################################################ | 100%

InvalidArchiveError('Error with archive C:\Users\mihae\Anaconda3\pkgs\yfinance-0.1.54-py_0.tar.bz2. You probably need to delete and re-download or re-create this file. Message from libarchive was:\n\nCould not unlink (errno=22, retcode=-25, archive_p=1835644343904)')_
"
I've tried the suggested solution (delete and try again) but I haven't much success.

Could you please support me?

Thanks a lot,
Adriana

Error: ValueError: operands could not be broadcast together with shapes (12,) (11,)

I am running the following backtesting with monthly returns:

# =============================================================================
# Backtesting strategy - I : Monthly portfolio rebalancing
# Author : Mayank Rasu

# Please report bug/issues in the Q&A section
# =============================================================================

import numpy as np
import pandas as pd
pd.core.common.is_list_like = pd.api.types.is_list_like
import pandas_datareader.data as pdr
import datetime
import copy
import quantstats as qs

# Download historical data (monthly) for DJI constituent stocks
tickers = ["MMM","AXP","T","BA","CAT","CVX","CSCO","KO", "XOM","GE","GS","HD",
           "IBM","INTC","JNJ","JPM","MCD","MRK","MSFT","NKE","PFE","PG","TRV",
           "UNH","VZ","V","WMT","DIS","SPY","QQQ","TLT","LQD","GLD","SLV","IEI","AAPL"]

ohlc_mon = {} # directory with ohlc value for each stock            
attempt = 0 # initializing passthrough variable
drop = [] # initializing list to store tickers whose close price was successfully extracted
while len(tickers) != 0 and attempt <= 5:
    tickers = [j for j in tickers if j not in drop] # removing stocks whose data has been extracted from the ticker list
    for i in range(len(tickers)):
        try:
            ohlc_mon[tickers[i]] = pdr.get_data_yahoo(tickers[i],datetime.date.today()-datetime.timedelta(5500),datetime.date.today(),interval='m')
            ohlc_mon[tickers[i]].dropna(inplace = True)
            drop.append(tickers[i])       
        except:
            print(tickers[i]," :failed to fetch data...retrying")
            continue
    attempt+=1
 
tickers = ohlc_mon.keys() # redefine tickers variable after removing any tickers with corrupted data

################################Backtesting####################################

# calculating monthly return for each stock and consolidating return info by stock in a separate dataframe
ohlc_dict = copy.deepcopy(ohlc_mon)
return_df = pd.DataFrame()
for ticker in tickers:
    print("calculating monthly return for ",ticker)
    ohlc_dict[ticker]["mon_ret"] = ohlc_dict[ticker]["Adj Close"].pct_change()
    return_df[ticker] = ohlc_dict[ticker]["mon_ret"]

# function to calculate portfolio return iteratively
def pflio(DF,m,x):
    """Returns cumulative portfolio return
    DF = dataframe with monthly return info for all stocks
    m = number of stock in the portfolio
    x = number of underperforming stocks to be removed from portfolio monthly"""
    df = DF.copy()
    
    portfolio = []
    monthly_ret = [0]
    for i in range(1,len(df)):
        if len(portfolio) > 0:
            monthly_ret.append(df[portfolio].iloc[i,:].mean())
            bad_stocks = df[portfolio].iloc[i,:].sort_values(ascending=True)[:x].index.values.tolist()
            portfolio = [t for t in portfolio if t not in bad_stocks]
        fill = m - len(portfolio)
        new_picks = df.iloc[i,:].sort_values(ascending=False)[:fill].index.values.tolist()
        portfolio = portfolio + new_picks
        print(portfolio)
        
    monthly_ret_df = pd.DataFrame(np.array(monthly_ret),columns=["mon_ret"])
    
    return monthly_ret_df

Strategy = pflio(return_df,6,3)
Strategy["Date"] = return_df[1:].index.values
Strategy.set_index("Date", inplace = True)

#calculating KPIs for Index buy and hold strategy over the same period
SP500 = pdr.get_data_yahoo("^GSPC",datetime.date.today()-datetime.timedelta(5500),datetime.date.today(),interval='m')
SP500["mon_ret"] =SP500["Adj Close"].pct_change()

#len(DJI["mon_ret"][1:])

qs.reports.html(Strategy["mon_ret"], SP500["mon_ret"][1:], output='report2.html', title = "Monthly portfolio rebalancing")

But when requesting the report it throws me the following error:

File "C:\Users\Alexrios22\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\nanops.py", line 127, in f
    result = alt(values, axis=axis, skipna=skipna, **kwds)

  File "C:\Users\Alexrios22\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\nanops.py", line 479, in nanmean
    the_sum = _ensure_numeric(values.sum(axis, dtype=dtype_sum))

  File "C:\Users\Alexrios22\AppData\Roaming\Python\Python38\site-packages\numpy\core\_methods.py", line 38, in _sum
    return umr_sum(a, axis, dtype, out, keepdims, initial, where)

ValueError: operands could not be broadcast together with shapes (12,) (11,) 


During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File "C:\Users\Alexrios22\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\nanops.py", line 130, in f
    result = alt(values, axis=axis, skipna=skipna, **kwds)

  File "C:\Users\Alexrios22\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\nanops.py", line 479, in nanmean
    the_sum = _ensure_numeric(values.sum(axis, dtype=dtype_sum))

  File "C:\Users\Alexrios22\AppData\Roaming\Python\Python38\site-packages\numpy\core\_methods.py", line 38, in _sum
    return umr_sum(a, axis, dtype, out, keepdims, initial, where)

ValueError: operands could not be broadcast together with shapes (12,) (11,) 


During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File "C:\Users\Alexrios22\Downloads\Trading\Curso Algorithmic Trading And Quantitative Analysis Using Python\Market Map\Rebalancing\Rebalancing.py", line 82, in <module>
    qs.reports.html(Strategy["mon_ret"], SP500["mon_ret"][1:], output='report2.html', title = "Monthly portfolio rebalancing")

  File "C:\Users\Alexrios22\AppData\Local\Programs\Python\Python38\lib\site-packages\quantstats\reports.py", line 121, in html
    _plots.yearly_returns(returns, benchmark, grayscale=grayscale,

  File "C:\Users\Alexrios22\AppData\Local\Programs\Python\Python38\lib\site-packages\quantstats\_plotting\wrappers.py", line 362, in yearly_returns
    hline=returns.mean(),

  File "C:\Users\Alexrios22\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\generic.py", line 10945, in stat_func
    return self._reduce(f, name, axis=axis, skipna=skipna,

  File "C:\Users\Alexrios22\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\series.py", line 3626, in _reduce
    return op(delegate, skipna=skipna, **kwds)

  File "C:\Users\Alexrios22\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\nanops.py", line 76, in _f
    return f(*args, **kwargs)

  File "C:\Users\Alexrios22\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\nanops.py", line 138, in f
    raise TypeError(e)

TypeError: operands could not be broadcast together with shapes (12,) (11,) 

I had already run it before, and it hadn't given me that error, but now it does.

when rf is not equal to zero, metric report doesn't look correct.

qs.reports.full(stock,benchmark='^NSEI',rf=0.065)

Performance Metrics
Strategy Benchmark


Start Period 2014-11-14 2014-11-14
End Period 2019-11-14 2019-11-14
Risk-Free Rate 0.06% 0.06%
Time in Market 100.0% 100.0%

Cumulative Return -100.0% -100.0%
CAGR% -100.0% -100.0%
Sharpe -62.45 -118.52
Sortino -15.39 -15.73

Profit factor calculation

Is there any reason why you calculate profit factor as

return abs(returns.sum() / returns[returns < 0].sum())

as opposed to:

return abs(returns[returns > 0].sum() / returns[returns < 0].sum())

I thought normally profit factor is total profit / total loss

Errors when there are no drawdowns

Hello,

First of all, thank you very much for releasing this lib publicly. I've been using it since it's so much simpler to use than many other ones.

I did come across a problem when there aren't any drawdowns or if there are fewer than 5 drawdowns. The problem is in at least two places that I've seen.

In stats._drawdown_details(drawdown), when returning None here, some code later expects a DataFrame and therefore it fails.

# no drawdown :)
if len(starts) == 0:
    return None

Even if above we return an empty DataFrame with the right column names, the code that uses this function still fails because range(1,6) is assigned to an index:
E.g. in reports.full()

dd_info = _stats.drawdown_details(dd).sort_values(
        by='max drawdown', ascending=True)[:5]
dd_info.index = range(1, 6)   # <-- Fails here

problem to visualize heatmap

Hi there Ran!
First of all, thanks for this piece of art you've made. It's been working great for my needs. I really appreciate the correlation heatmap provided, but after some time using it I got a visualization problem, having the edge boxes cut in half. Any ideas for fixing that?
Captura de Tela 2019-09-19 às 19 28 42

CSV data entry

Thank you very much for the very good work!

I am using quantstats to evaluate my trading strategies and I have some doubts about the data that quantstats is able to read.

A strategy that I trade signal to signal and is in a trade all the time works well.

Use one csv with one date and returns column like this
image

But in a strategy that opens one day and closes another day, and in between days may pass no longer.

1- Can you put two dates, one entry and one exit? How would the code for this be?

Another question, and I don't know if this is covered by quantstats, is the function of pyramid.

2-I have a strategy in which I do up to three pyramid trades, but when I enter the data into quantstats, I compose them too much and it gives unrealistic results.

3-May I add the option of non-compounding returns?

I think that in the case of the pyramid this will be an option.

Enter each trade with a fixed amount.

Shared one spreadshet with the trades:

The most important stats are : signal type, date with hour, price, contract (strategy is set for take profit 35% in certain circumstances, profit %)

https://docs.google.com/spreadsheets/d/1OdI3e38OsEDSh5gQLdNtW75DaHtgshpvRI6HofaE00I/edit#gid=0

I'm not sure what kind of analysis I can do for this strategy to get the right results.

Sorry about the long post. Cheers and thanks.

utils.py:line94, .ix is deprecated resulting in FutureWarning

FutureWarning error in the utils.py module at line 94 in the rebase function.

Pandas' .ix is now deprecated and a simple change to .iloc[0] in the rebase function fixes this. I've run this in isolation and tested against both series and dataframe timeseries prices and it works well.

Import Error

After the last update of the code when importing quantstats it returns the error:

AttributeError: 'str' object has no attribute 'magic

I checked the code and it's an error on line 278 of utils.py. Where it reads

shell.magic("matplotlib inline")

should be

get_ipython().magic("matplotlib inline").

You're doing a great job! Go for it!

Doubt regarding the kind of returns for input

First of all, I would like to thank for this really awesome tool. I have been trying to use it for some time and from the examples I see that almost all the functions need returns as input to generate the stats and tearsheet etc.
My doubt is that what kind of returns does this library assume. Is it simple returns calculated using pct_change() in pandas or log returns calculated using np.log(close_price).diff().

Initial Update

The bot created this issue to inform you that pyup.io has been set up on this repo.
Once you have closed it, the bot will open pull requests for updates as soon as they are available.

Monthly return heat chart cutting off

I'm running the reports.plot with mode="full" and the top and bottom rows of the monthly returns chart is getting clipped (please see the attached screenshot). I was wondering if there is a way to add a bit of spacing on the top and bottom to get it to render properly.

Screen Shot 2020-02-07 at 1 55 47 AM

Thanks for the help.

Error when final date is not today() and when number of drawdowns are less than 5

Hello,

First of all, thank you for your amazing library and work, is great!

I'm using it and I think I have discovered two little bugs:
1.- In reports.py line 71; today = _dt.today()
This line is good if the final date of the returns is equal to today(), but if we are doing a backtest, and the final date of teh returns where 2 years ago, this line is not correct. I think this can be solved changing that line to:
today = df.index[-1]

2.- In reports.py line 217; dd_info.index = range(1, 6)
The code breaks were there is less than 5 drawdowns. This can happen easily if our portfolio don't do to many operations. I think this can be fixed changing that line to:
dd_info.index = range(1, min(6, len(dd_info)+1))

3.- Finally, when I execute the some reports that include plots, I get the following error (executing the code from pycharm console):

...\lib\site-packages\quantstats\_plotting\wrappers.py:154: MatplotlibDeprecationWarning:

Passing the block parameter of show() positionally is deprecated since Matplotlib 3.1; the parameter will become keyword-only in 3.3.

I have tried to change every _plt.show(fig) to_plt.show(fig, block=False)and still not working, any idea of how can be solved that?

Risk free rate isn't daily

In html report we pass risk-free rate in year basis, but in calculating the excess_returns we have to substract the daily change.

def to_excess_returns(returns, rf, nperiods=None):
    """
    Calculates excess returns by subtracting
    risk-free returns from total returns

    Args:
        * returns (Series, DataFrame): Returns
        * rf (float, Series, DataFrame): Risk-Free rate(s)
        * nperiods (int): Optional. If provided, will convert rf to different
            frequency using deannualize
    Returns:
        * excess_returns (Series, DataFrame): Returns - rf
    """
    if not isinstance(rf, float):
        rf = rf[rf.index.isin(returns.index)]

    if nperiods is not None:
        # deannualize
        rf = _np.power(1 + returns, 1. / nperiods) - 1.

    return returns - rf

Extracting results from stable baselines environment

Hello,
after creating a model in the stable baselines library anytrading (https://github.com/AminHP/gym-anytrading) and running the following code:

env = gym.make('stocks-v0', frame_bound=(50, 100), window_size=10)
model = DQN('MlpPolicy', env, tensorboard_log="D:\ReinforcementLearning\BaseLines\Trading\Tensorboard",
            verbose=2)
results = model.learn(int(1000))

how do I use the results to compare with a benchmark in quantstats?
Currently the results doesn't hold the data that quantstats expect to be able to use in conjunction with qs.reports.html(results, "SPY", output="D:\ReinforcementLearning\BaseLines\Trading\Myreport.html")

Problem when daily return >= 100%

Hi,

I've come across an edge case that took me quite a while to debug.
Basically when a daily return is >= 100% (during backtesting, pennystocks etc), utils._prepare_prices() thinks that the input series has already been converted to prices and it does nothing. This obviously messes up the calculations.

elif data.min() <= 0 and data.max() < 1:
        data = to_prices(data, base)

For now as a hack I just clip all my returns to 0.9999.

Any thoughts on how to deal with this, given that it is an edge case... unfortunately :-)?
I think putting an or instead of the and might be more robust, but still not foolproof.

Feedback

As mentioned in the readme to let you know feedback..

Its a great project and wonderful with backtrader too.

I prefer to pyfolio

Keep up the good work!

leap year issue

got this data when running datasets including 02/29/2020
Traceback (most recent call last):
File "report.py", line 28, in
qs.reports.html(series, output='ASSET.html')
File "/usr/local/lib/python3.7/site-packages/quantstats/reports.py", line 61, in html
compounded=compounded)[2:]
File "/usr/local/lib/python3.7/site-packages/quantstats/reports.py", line 389, in metrics
df[df.index >= _dt(today.year-3, today.month, today.day)
ValueError: day is out of range for month

incorrect EOY Returns

Hi Ran,

I'm trying to get full report from cumulative returns pandas dataframe. Everything seems to be fine except EOY Returns.

2015 | 4063561685.19% | inf%
2016 | 5685063513.11% | inf%
2017 | 8068012580.76% | inf%
2018 | 9992995288.14% | inf%
2019 | 5817419000.9% | inf%


MTD | 0.55%
3M | 10.35%
6M | 15.35%
YTD | 12.37%
1Y | 5.07%
3Y (ann.) | 20.56%
5Y (ann.) | 26.93%
10Y (ann.) | 26.93%
All-time (ann.) | 26.93%

API use

Can I use this library to monitor my live performace on an API for eg: Binance.

ValueError: cannot convert float NaN to integer

Hi, I think that when there is no drawdown, we will get the error:

ValueError: cannot convert float NaN to integer

This problem was previously closed without being completely fixed #2

Here's the error traceback:

Traceback (most recent call last):
  File "test.py", line 269, in <module>
    qs.reports.html(returns['net_worth'], benchmark, output=os.path.join(projectDir, 'report.html'))
  File "/home/athena/anaconda3/envs/unicorn/lib/python3.8/site-packages/quantstats/reports.py", line 58, in html
    mtrx = metrics(returns=returns, benchmark=benchmark,
  File "/home/athena/anaconda3/envs/unicorn/lib/python3.8/site-packages/quantstats/reports.py", line 299, in metrics
    dd = _calc_dd(df, display=(display or "internal" in kwargs))
  File "/home/athena/anaconda3/envs/unicorn/lib/python3.8/site-packages/quantstats/reports.py", line 587, in _calc_dd
    'Longest DD Days': str(round(bench_dd.sort_values(
ValueError: cannot convert float NaN to integer

Using quantstats 0.0.25, pandas 1.0.3

Thanks!

Charts don't get displayed

Hello people,
I'm trying to run the examples but for some reason the charts don't get displayed. It looks like the window flashes and closes itself straight after.
Has anyone else faced similar issue?
Thanks all

Help needed - adaption of Quantstats in order to do Backtest Analysis (Cryptotrading)

backtest-result-2020-08-19_11-42-18.zip

Thanks for this awesome open source project. I try to link it to another exciting project which is -> https://github.com/freqtrade/freqtrade

In Freqtrade you can do backtests with the strategy being crafted - however the analysis tools are currently limited. The backtest results are exported as .json files (example enclosed).

I have tried to "cast" the backtest results in the input format of Quantstats, which was working well to the point of plotting the snapshot. Here is my code - probably not the most elegant way (I am not a coder):

import quantstats as qs
from freqtrade.data.btanalysis import load_backtest_data

# extend pandas functionality with metrics, etc.
qs.extend_pandas()

# load backtest data
backtest = load_backtest_data('/home/andreas/freqtrade/user_data/backtest_results/backtest-result-2020-08-19_11-42-18.json') 

# define stake amount and compute equity curve
stake_amount = 100 
max_open_trades = 10
stake_amount_total = stake_amount * max_open_trades

backtest['profit_amount'] = (backtest['profit_percent']) * stake_amount  
backtest['cum_profit'] = backtest['profit_amount'].cumsum() # cumulated profits in stake currency
          
# prepare data for Quantstat format
backtest = backtest.set_index('close_date')
daily_resampled_data = backtest.cum_profit.resample('D').mean()
daily_resampled_data1 = daily_resampled_data.apply(lambda x: x + stake_amount_total) # add stake amount x max open trades

# feed own data into Quantstat "stock" algo
stock = daily_resampled_data1.pct_change()

# show performance plot
qs.plots.snapshot(stock, title='Performance')

When trying to apply the most interesting function (full report, benchmark e.g. LTC-USD) I got an error message:

qs.reports.basic(stock, "LTC-USD")

qs.reports.basic(stock, "LTC-USD")
<IPython.core.display.HTML object>
Traceback (most recent call last):

  File "<ipython-input-217-a1e5d119cf6e>", line 1, in <module>
    qs.reports.basic(stock, "LTC-USD")

  File "/home/andreas/anaconda3/lib/python3.7/site-packages/quantstats/reports.py", line 259, in basic
    compounded=compounded)

  File "/home/andreas/anaconda3/lib/python3.7/site-packages/quantstats/reports.py", line 299, in metrics
    dd = _calc_dd(df, display=(display or "internal" in kwargs))

  File "/home/andreas/anaconda3/lib/python3.7/site-packages/quantstats/reports.py", line 588, in _calc_dd
    by='days', ascending=False)['days'].values[0])),

ValueError: cannot convert float NaN to integer

What to do here?

Issues with running commands on Visual Studio

Hi @ranaroussi ,
The static output works fine on visual studio but charts are not showing any output.
1

qs.plots.snapshot(df0['PPL_Return'], title='PPL Performance')`

This command runs but no output is displayed. Is there any other command to add so that output can be displayed?

CAGR seems incorrect

Hi,

Thanks for your library I'm using it.

I was getting a negative CAGR when my total return was positive. There are 2 issues I think, firstly the year calculation does not cope with periods less than a year. Secondly in the total return part you need to add back 1.0 before you do the power calculation.

E.g. If I make 10% for 2 years then my total returns should be 21%. My CAGR should obviously be 10%. To achieve this calculation I need to compute (0.21 + 1.0) ** (1/2.0) - 1

# years = len(set(returns.index.year))
years = (returns.index[-1] - returns.index[0]).days/365.0

# res = abs(total / 1.0) ** (1.0 / years) - 1
res = abs(total + 1.0) ** (1.0 / years) - 1

output

hello everyone, how much I try to do :
qs.reports.html(returns=stock,benchmark=bench,output="report.html")

I get the following error:

UnicodeEncodeError Traceback (most recent call last)
in
----> 1 qs.reports.html(returns=stock,benchmark=bench,output='1.html')

~\Miniconda3\envs\quant\lib\site-packages\quantstats\reports.py in html(returns, benchmark, rf, grayscale, title, output, compounded)
    205 
    206     with open(output, 'w') as f:
--> 207         f.write(tpl)
    208 
    209 

~\Miniconda3\envs\quant\lib\encodings\cp1252.py in encode(self, input, final)
     17 class IncrementalEncoder(codecs.IncrementalEncoder):
     18     def encode(self, input, final=False):
---> 19         return codecs.charmap_encode(input,self.errors,encoding_table)[0]
     20 
     21 class IncrementalDecoder(codecs.IncrementalDecoder):

UnicodeEncodeError: 'charmap' codec can't encode character '\u2212' in position 649916: character maps to <undefined>

Any solution?
Thank you very much for your work!

Question/Feature Request

Hey thanks so much for your great work here! It is super useful. Would it be possible to pass your functions a list of Tickers and Weights so i can get a full report on a buy and hold portfolio over time? Thanks so much! :)

Settings to change the default colors (blue and yellow) of curves/graphs

Dear Project Team,
Not an issue per se, more a question. Is there an easy way to override the default colors used by Quantstats curves & graphs? I ve looked a bit the code; I have seen where there are defined. However, I d like to modify these colors without "forking"/duplicating the whole project?
Many thanks in advance
Regards,

Type Error on EOY Returns

Hi Ran,

I have been using quantstats to generate a complete report of my portfolio with the function qs.reports.html but it gave me a TypeError. After exploring the error a little bit more, if I use the function qs.reports.full(trader.daily_returns, "SPY") in a jupyter notebook it gives the Output until the Cumulative Returns vs SPY (Volatility Matched). However while trying to print the graph EOY Returns vs Benchmark, the following error occurs:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-27-649f47ec8503> in <module>
----> 1 qs.reports.full(trader.daily_returns, "SPY")

~\Anaconda3\lib\site-packages\quantstats\reports.py in full(returns, benchmark, rf, grayscale, figsize, display, compounded)
    247 
    248     plots(returns=returns, benchmark=benchmark,
--> 249           grayscale=grayscale, figsize=figsize, mode='full')
    250 
    251 

~\Anaconda3\lib\site-packages\quantstats\reports.py in plots(returns, benchmark, grayscale, figsize, mode, compounded)
    509                           grayscale=grayscale,
    510                           figsize=(figsize[0], figsize[0]*.5),
--> 511                           show=True, ylabel=False)
    512 
    513     _plots.histogram(returns, grayscale=grayscale,

~\Anaconda3\lib\site-packages\quantstats\_plotting\wrappers.py in yearly_returns(returns, benchmark, fontname, grayscale, hlw, hlcolor, hllabel, match_volatility, log_scale, figsize, ylabel, subtitle, compounded, savefig, show)
    371                             grayscale=grayscale,
    372                             ylabel=ylabel,
--> 373                             subtitle=subtitle, savefig=savefig, show=show)
    374 
    375 

~\Anaconda3\lib\site-packages\quantstats\_plotting\core.py in plot_returns_bars(returns, benchmark, returns_label, hline, hlw, hlcolor, hllabel, resample, title, match_volatility, log_scale, figsize, grayscale, fontname, ylabel, subtitle, savefig, show)
    110     if benchmark is None:
    111         colors = colors[1:]
--> 112     df.plot(kind='bar', ax=ax, color=colors)
    113 
    114     fig.set_facecolor('white')

~\Anaconda3\lib\site-packages\pandas\plotting\_core.py in __call__(self, *args, **kwargs)
    792                     data.columns = label_name
    793 
--> 794         return plot_backend.plot(data, kind=kind, **kwargs)
    795 
    796     def line(self, x=None, y=None, **kwargs):

~\Anaconda3\lib\site-packages\pandas\plotting\_matplotlib\__init__.py in plot(data, kind, **kwargs)
     60             kwargs["ax"] = getattr(ax, "left_ax", ax)
     61     plot_obj = PLOT_CLASSES[kind](data, **kwargs)
---> 62     plot_obj.generate()
     63     plot_obj.draw()
     64     return plot_obj.result

~\Anaconda3\lib\site-packages\pandas\plotting\_matplotlib\core.py in generate(self)
    277     def generate(self):
    278         self._args_adjust()
--> 279         self._compute_plot_data()
    280         self._setup_subplots()
    281         self._make_plot()

~\Anaconda3\lib\site-packages\pandas\plotting\_matplotlib\core.py in _compute_plot_data(self)
    412         # no non-numeric frames or series allowed
    413         if is_empty:
--> 414             raise TypeError("no numeric data to plot")
    415 
    416         # GH25587: cast ExtensionArray of pandas (IntegerArray, etc.) to

TypeError: no numeric data to plot

image

Cumulative return calc query

I have a dataframe or series with daily returns for a model I have built... it contains just 2019 data - Jan 2nd to Dec 31st. The cumsum of that Close column in 17.86%. But when I run it through Quantstats, the HTML output is showing a cumulative return of 17.2%.
Even the sum of the monthly returns from the HTML shows 17.84%
qs2
qs1

Annualization Incorrect for Crypto

Currently the stats.py annualizes using 252 period. There needs to be an option for 365 for crypto.

For running HTML reports, I can't see a straightforward way to annualise without overwritting the stats.py file.

Ideally this should be an input in reports.py.

Thanks

Quantstats report to PDF

Hi,

I'd like to create a nice PDF using Quantstats.

Is there a better way to do it other than:

  • Run Python code to export as "HTML"
  • Open HTML in Chrome
  • Print as PDF

The problem is, a number of the charts get cut off and split across pages.

Please Let me know if there is a nice way to save and share these reports, ideally PDF!

Thank you,
CWSE

Evaluating a watchlist

Thanks for providing the great example for evaluating FB.
Can quantstats be used to evaluate a watchlist of stocks?

Issue with qs.reports.html in Jupyter

Hi Ran,
I have an issue with "qs.reports.html". It works when I use "output=". But when I ran it on Jupyter notebook I don't get the output as you see in the screenshot. Do you know this issue with Jupyter?
I add another screenshot from inspect look like something jquery erroer

Thank you in advance
image
image

ErrorMessage

When I execute "qs.utils.download_returns('FB')" I get the following error message: AttributeError: module 'pandas.core.common' has no attribute '_dict_keys_to_ordered_list'.

The graphs and summary look really nice and powerful - thus it would be nice to use this library.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.