Metrics using Alternative Portfolio Theory
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © TechnicusCapital

//@version=5

// @description Portfolio metrics using alternative portfolio theory
library("APT_Metrics", overlay = true)

import TradingView/ta/5 as ta

// @function Calculates APT metrics
// @param init Starting Equity (strategy.initial)
// @param src Current Equity Curve (strategy.equity)
// @param start Start date (UNIX)
// @param end End Date (UNIX)
// @param alpha Confidence interval for DaR/CDaR. Defval = 0.05
// @returns Table with APT metrics
export metrics(float init, float cur, int start, int end, float alpha = .05) =>
	var inDD = false
	var ddBegin = 0.00
	var float ddLowPrice = na
	var ddLow = 0.00
	var dd = 0.00
	var ddArr = array.new<float>()
	var ui = 0.00

	if cur < cur[3] and not inDD
		ddLowPrice := cur
		inDD := true
		ddBegin := cur
		array.push(ddArr, 0)
	if inDD and cur < ddBegin
		ddLowPrice := math.min(ddLowPrice, cur)
		dd := (ddBegin - cur)/ddBegin
		ddLow := (ddBegin - ddLowPrice)/ddBegin
		array.set(ddArr, array.size(ddArr) -1, ddLow)
	if inDD and cur > ddBegin
		if ddLow < .01 and array.size(ddArr) > 0
			array.remove(ddArr, array.size(ddArr) -1)
		inDD := false
		dd := 0.00

	ui := array.stdev(ddArr)
	returns_length = 252
	volatility_length = 1280

	log_returns = ta.roc(cur, 1)
	ret_sma = ta.sma(log_returns, returns_length)
	ret_annual = ret_sma  * returns_length
	ret_norm = ret_annual * 100

	var entryPrice = 0.00
	var exitPrice = 0.00
	if time <= end
		entryPrice := close
	cagr = ta.cagr(start, init, end, cur)/100
	hv = ta.stdev(log_returns, volatility_length) * math.sqrt(returns_length)
	hv_norm = hv/100

	upi = (cagr)/(ui)

	DaR = array.percentile_nearest_rank(ddArr, (1-alpha)*100)
	cdarArr = array.new<float>()
	for each in ddArr
		if each > DaR
			array.push(cdarArr, each)
	CDaR = array.avg(cdarArr)
	array.clear(cdarArr)

	CDaR_est = array.percentile_nearest_rank(ddArr, 95)

	pitfall = CDaR/hv_norm

	penalized_risk = ui * pitfall

	SR = cagr/penalized_risk

	table perfTable1 = table.new(position.bottom_right, 2, 9, border_color = color.yellow, border_width = 1)

	table.cell(perfTable1, 0, 0, "ASPECT",       text_color = color.white)
	table.cell(perfTable1, 1, 0, "VALUE", text_color = color.white)   

	table.cell(perfTable1, 0, 1, "Ulcer Index", text_color = color.white)
	table.cell(perfTable1, 1, 1, str.tostring(math.round(ui*100, 2)) + "%", text_color = color.white)

	table.cell(perfTable1, 0, 2, "Ulcer Performance Index", text_color = color.white)
	table.cell(perfTable1, 1, 2, str.tostring(math.round(upi,2)), text_color = color.white)

	table.cell(perfTable1, 0, 3, "CDaR", text_color = color.white)
	table.cell(perfTable1, 1, 3, str.tostring(math.round(CDaR*100, 2)) + "%", text_color = color.white)


	//The Pitfall represents the average loss of the biggest drawdowns expressed in units of volatility.
	table.cell(perfTable1, 0, 4, "Pitfall Indicator", text_color = color.white)
	table.cell(perfTable1, 1, 4, str.tostring(math.round(pitfall, 2)), text_color = color.white)

	table.cell(perfTable1, 0, 5, "Penalized Risk", text_color = color.white)
	table.cell(perfTable1, 1, 5, str.tostring(math.round(penalized_risk*100,2)) + "%", text_color = color.white)

	table.cell(perfTable1, 0, 6, "Serenity Ratio", text_color = color.white)
	table.cell(perfTable1, 1, 6, str.tostring(math.round(SR, 2)), text_color = color.white)

