Exemple #1
0
def get_tracking_error(strategy, benchmark, start_date, end_date) -> float:
    '''calculates the tracking error of a strategy compared to a benchmark'''
    assert check_prices(strategy=strategy, benchmark=benchmark)
    assert check_time(start_date=start_date, end_date=end_date)

    ann_ex_r = get_annualized_excess_return(strategy, benchmark, start_date,
                                            end_date)
    ir = get_information_ratio(strategy, benchmark, start_date, end_date)

    tracking_error = ann_ex_r / ir
    return tracking_error
Exemple #2
0
def get_daily_returns(prices) -> pd.Series:
    '''calculates the daily returns of a prices time-series'''
    assert check_prices(prices=prices)
    prices.sort_index(inplace=True)  # make sure dates is in ascending order
    daily_change = [0]
    for i in range(1, len(prices)):
        yesterday = prices[i - 1]
        today = prices[i]
        change = round((today - yesterday) / yesterday, 4)
        daily_change.append(change)

    daily_change = pd.Series(data=daily_change, index=prices.index)
    return daily_change
Exemple #3
0
def get_risk_adjusted_return(prices, start_date, end_date) -> float:
    '''calculates the risk-adjusted return of a prices time-series between two dates'''
    assert check_prices(prices=prices)
    assert check_time(start_date=start_date, end_date=end_date)

    prices = prices.loc[start_date:end_date]
    start_date, end_date = prices.index[0], prices.index[-1]

    ann_rtn = get_annualized_return(prices, start_date, end_date)
    vo = get_strategy_volatility(prices, start_date, end_date)

    risk_adj_rtn = ann_rtn / vo
    risk_adj_rt = round(risk_adj_rtn, 4)
    return risk_adj_rt
Exemple #4
0
def get_cumulative_return(prices, start_date, end_date) -> float:
    '''calculates the cumulative return between two dates'''
    assert check_prices(prices=prices)
    assert check_time(start_date=start_date, end_date=end_date)

    prices.sort_index(inplace=True)  # make sure dates is in ascending order
    prices = prices.loc[start_date:end_date]
    start_date, end_date = prices.index[0], prices.index[-1]
    cost = prices[start_date]
    revenue = prices[end_date]
    cum_rtn = (revenue - cost) / cost

    cum_rtn = round(cum_rtn, 4)
    return cum_rtn
Exemple #5
0
def get_strategy_volatility(prices, start_date, end_date) -> float:
    '''calculates the volatility of a prices time-series between two dates'''
    assert check_prices(prices=prices)
    assert check_time(start_date=start_date, end_date=end_date)

    change = prices.pct_change().dropna()
    change = change[change != 0]

    change_avg = np.mean(change)
    daily_sum = np.sum([(c - change_avg)**2 for c in change])

    vo = np.sqrt((250 / ((end_date - start_date).days - 1)) * daily_sum)
    vo = round(vo, 4)
    return vo
Exemple #6
0
def get_excess_return(strategy, benchmark, start_date, end_date) -> float:
    '''calculates the excess return of a strategy over a benchmark between two dates'''
    assert check_prices(strategy=strategy, benchmark=benchmark)
    assert check_time(start_date=start_date, end_date=end_date)

    strategy = strategy.loc[start_date:end_date]
    benchmark = benchmark.loc[start_date:end_date]
    start_date, end_date = strategy.index[0], strategy.index[-1]

    r_strategy = get_daily_returns(strategy)
    r_benchmark = get_daily_returns(benchmark)

    excess_return = (r_strategy - r_benchmark).cumsum()
    excess_return = round(excess_return, 4)
    return excess_return
Exemple #7
0
def get_annualized_excess_return(strategy, benchmark, start_date,
                                 end_date) -> float:
    '''calculate the annuliazed return of a strategy compared to a benchmark'''
    assert check_prices(strategy=strategy, benchmark=benchmark)
    assert check_time(start_date=start_date, end_date=end_date)

    strategy = strategy.loc[start_date:end_date]
    benchmark = benchmark.loc[start_date:end_date]
    start_date, end_date = strategy.index[0], strategy.index[-1]

    strategy_return = get_annualized_return(strategy, start_date, end_date)
    market_return = get_annualized_return(benchmark, start_date, end_date)

    ann_ex_rtn = strategy_return - market_return
    ann_ex_rtn = round(ann_ex_rtn, 4)
    return ann_ex_rtn
Exemple #8
0
def get_sharpe_ratio(prices, start_date, end_date, risk_free=0.04) -> float:
    '''calculates the sharpe ratio of a prices time-series between two dates'''
    assert check_prices(prices=prices)
    assert check_time(start_date=start_date, end_date=end_date)
    assert 0 <= risk_free <= 1, 'the risk free rate must be between 0 and 1'

    prices = prices.loc[start_date:end_date]
    start_date, end_date = prices.index[0], prices.index[-1]

    ann_rtn = get_annualized_return(prices, start_date, end_date)
    excess_rtn = ann_rtn - risk_free
    vo = get_strategy_volatility(prices, start_date, end_date)

    sharpe_ratio = excess_rtn / vo
    sharpe_ratio = round(sharpe_ratio, 4)
    return sharpe_ratio
Exemple #9
0
def get_max_drawdown(prices, start_date, end_date) -> float:
    '''calculates the maximum drawdown of a prices time-series between two dates'''
    assert check_prices(prices=prices)
    assert check_time(start_date=start_date, end_date=end_date)

    prices = prices.loc[start_date:end_date]
    start_date, end_date = prices.index[0], prices.index[-1]
    max_drawdown = 0
    # for each day, get the lowest price in the period after
    for day in prices.index:
        day_price = prices[day]
        lowest = prices.loc[day:].min()
        drawdown = (day_price - lowest) / day_price
        if drawdown > max_drawdown:
            max_drawdown = drawdown

    max_drawdown = round(max_drawdown, 4)
    return max_drawdown
Exemple #10
0
def get_beta(strategy, benchmark, start_date, end_date) -> float:
    '''calculates the beta of a prices time-series between two dates'''
    assert check_prices(strategy=strategy, benchmark=benchmark)
    assert check_time(start_date=start_date, end_date=end_date)

    strategy = strategy.loc[start_date:end_date]
    benchmark = benchmark.loc[start_date:end_date]
    start_date, end_date = strategy.index[0], strategy.index[-1]

    r_strategy = get_daily_returns(strategy)
    r_benchmark = get_daily_returns(benchmark)

    var = np.var(r_benchmark, ddof=1)
    cov = np.cov(r_strategy, r_benchmark)[0][1]

    beta = cov / var
    beta = round(beta, 4)
    return beta
Exemple #11
0
def get_information_ratio(strategy, benchmark, start_date, end_date) -> float:
    '''calculates the information ratio of a prices time-series between two dates'''
    assert check_prices(strategy=strategy, benchmark=benchmark)
    assert check_time(start_date=start_date, end_date=end_date)

    excess_return = get_annualized_excess_return(strategy, benchmark,
                                                 start_date, end_date)

    strategy_daily = get_daily_returns(strategy)
    benchmark_daily = get_daily_returns(benchmark)

    strategy_daily = strategy_daily[strategy_daily != 0]
    benchmark_daily = benchmark_daily[benchmark_daily != 0]

    daily_excess_return = strategy_daily - benchmark_daily
    daily_stdev = np.std(daily_excess_return) * np.sqrt(250)

    ir = excess_return / daily_stdev
    ir = round(ir, 4)
    return ir
Exemple #12
0
def get_daily_win_rate(strategy, benchmark, start_date, end_date) -> float:
    '''calculates the daily win rate of a strategy compared to a benchmark'''
    assert check_prices(strategy=strategy, benchmark=benchmark)
    assert check_time(start_date=start_date, end_date=end_date)

    strategy = strategy.loc[start_date:end_date]
    benchmark = benchmark.loc[start_date:end_date]
    start_date, end_date = strategy.index[0], strategy.index[-1]

    r_strategy = get_daily_returns(strategy)
    r_benchmark = get_daily_returns(benchmark)

    daily_diff = r_strategy - r_benchmark
    win = 0
    for day in daily_diff:
        if day > 0:
            win += 1

    daily_win_rate = win / len(daily_diff)
    daily_win_rate = round(daily_win_rate, 4)
    return daily_win_rate
Exemple #13
0
def get_alpha(strategy,
              benchmark,
              start_date,
              end_date,
              risk_free=0.04) -> float:
    '''calculates the alpha of a prices time-series between two dates'''
    assert check_prices(strategy=strategy, benchmark=benchmark)
    assert check_time(start_date=start_date, end_date=end_date)
    assert 0 <= risk_free <= 1, 'the risk free rate must be between 0 and 1'

    strategy = strategy.loc[start_date:end_date]
    benchmark = benchmark.loc[start_date:end_date]
    start_date, end_date = strategy.index[0], strategy.index[-1]

    market_return = get_annualized_return(benchmark, start_date, end_date)
    beta = get_beta(strategy, benchmark, start_date, end_date)

    capm = risk_free + beta * (market_return - risk_free
                               )  # asset price under the CAPM model
    annualized_return = get_annualized_return(strategy, start_date, end_date)

    alpha = annualized_return - capm
    alpha = round(alpha, 4)
    return alpha
Exemple #14
0
def show_metrics(strategy, benchmark, holdings, df_price):
    '''
    prints out a chart that shows columns of metrics

    Parameters
    ----------
    strategy : pandas.Series
        the performance of the strategy being backtested
    benchmark : pandas.Series
        the performance of the benchmark used in backtest
    '''
    assert check_prices(strategy=strategy, benchmark=benchmark)

    start_date = strategy.index[0]
    end_date = strategy.index[-1]

    benchmark = benchmark.loc[start_date:end_date]

    date_range = pd.date_range(start=start_date, end=end_date)
    benchmark = benchmark.reindex(date_range, method='ffill')
    benchmark.fillna(method='bfill', inplace=True)

    cum_r = get_cumulative_return(strategy, start_date, end_date)
    ann_r = get_annualized_return(strategy, start_date, end_date)
    ann_ex_r = get_annualized_excess_return(strategy, benchmark, start_date,
                                            end_date)

    max_dd = get_max_drawdown(strategy, start_date, end_date)
    vo = get_strategy_volatility(strategy, start_date, end_date)
    risk_adj = get_risk_adjusted_return(strategy, start_date, end_date)
    sharpe = get_sharpe_ratio(strategy, start_date, end_date)
    ir = get_information_ratio(strategy, benchmark, start_date, end_date)
    beta = get_beta(strategy, benchmark, start_date, end_date)
    alpha = get_alpha(strategy, benchmark, start_date, end_date)
    win_r = get_win_rate(start_date, end_date, holdings, df_price)
    win_r_d = get_daily_win_rate(strategy, benchmark, start_date, end_date)
    pl = get_pl_ratio(start_date, end_date, holdings, df_price)
    to_r = get_turnover_ratio(start_date, end_date, holdings, df_price)
    trk_err = get_tracking_error(strategy, benchmark, start_date, end_date)

    print('\n============================================')
    print('| Key Metrics ')
    print('============================================')
    print(f'| Start Date:        {start_date.date()}')
    print(f'| End Date:          {end_date.date()}')
    print('============================================')
    print(f'| Cumulative Return: {round(cum_r*100, 2)}%')
    print(f'| Annualized Return: {round(ann_r*100, 2)}%')
    print(f'| Annualized Excess: {round(ann_ex_r*100, 2)}%')
    print(f'| Maximum Drawdown:  {round(max_dd*100, 2)}%')
    print('============================================')
    print(f'| Risk Adjusted:     {round(risk_adj, 3)}')
    print(f'| Information Ratio: {round(ir, 3)}')
    print(f'| Sharpe Ratio:      {round(sharpe, 3)}')
    print(f'| Volatility:        {round(vo, 3)}')
    print('============================================')
    print(f'| Alpha:             {round(alpha, 3)}')
    print(f'| Beta:              {round(beta, 3)}')
    print('============================================')
    print(f'| Win Rate:          {round(win_r*100, 2)}%')
    print(f'| Daily Win Rate:    {round(win_r_d*100, 2)}%')
    print(f'| Profit-Loss Ratio: {round(pl, 1)} : 1')
    print('============================================')
    print(f'| Turnover Ratio:    {round(to_r*100, 2)}%')
    print(f'| Tracking Error:    {round(trk_err*100, 2)}%')
    print('============================================')