Risk Management
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © weak_hand

//@version=5

// @description This library keeps your money in check, and is used for testing and later on webhook-applications too. It has four volatility functions and two of them can be used to calculate a Stop-Loss, like Average True Range. It also can calculate Position Size, and the Risk Reward Ratio. But those calculations don't take leverage into account.
library("RiskManagement")

calc_qty(float p = 0, float r = 2.0, float e = 0.0, float s = 0.0) =>	// This function calculates the quantity of contracts/shares/units.
	risk_per_trade = r <= 100 and r > 0.0 ? p * r / 100 : 0.0			// if risk is equal or below 100 then calculate risk amount, other wise take zero risk
    risk_per_unit = e > s ? e - s : s - e								// calculate ticks between entry and stop loss
	risk_per_trade / risk_per_unit										// calculate quantity of contracts/shares/units

// @function This function calculates the definite amount of contracts/shares/units you should use to buy or sell.  This value can used by `strategy.entry(qty)` for example.
// @param portfolio This is the total amount of the currency you own, and is also used by strategy.initial_capital, for example. The amount is needed to calculate the maximum risk you are willing to take per trade.
// @param risk This is the percentage of your Portfolio you willing to loose on a single trade. Possible values are between 0.1 and 100%. Same usecase with strategy(default_qty_type=strategy.percent_of_equity,default_qty_value=100), except its calculation the risk only.
// @param entry This is the limit-/market-price for the investment. In other words: The price per contract/share/unit you willing to buy or sell.
// @param stop_loss This is the limit-/market-price when to exit the trade, to minimize your losses.
// @param use_leverage This value is optional. When not used or when set to false then this function will let you invest your portfolio at max. 
// @param qty_as_integer This value is optional. When set to true this function will return a value used with integers. The largest integer less than or equal to the given number. Because some Broker/Exchanges let you trade hole contracts/shares/units only.
// @returns float
export position_size(float portfolio = 10000.0, float risk = 2.0, float entry = 0.0, float stop_loss = 0.0, bool use_leverage = false, bool qty_as_integer = false) => 
	float sum = portfolio > 0.0 ? calc_qty(portfolio,risk,entry,stop_loss) : 0.0
	float qty = not use_leverage ? sum : sum * entry > portfolio ? portfolio / entry : sum
	if qty_as_integer
		math.floor(qty)
	else
		qty	

// @function This function calculates the definite amount of currency you should use when going long or short.
// @param portfolio This is the total amount of the currency you own, and is also used by strategy.initial_capital, for example. The amount is needed to calculate the maximum risk you are willing to take per trade.
// @param risk This is the percentage of your Portfolio you willing to loose on a single trade. For example: 1 is 100% and 0,01 is 1%. Default amount is 0.02 (2%).
// @param entry This is the limit-/market-price for the current investment. In other words: The price per contract/share/units you willing to buy or sell.
// @param stop_loss This is the limit-/market-price when to exit the trade, to minimize your losses.
// @returns float
export position_size_currency(float portfolio = 10000.0, float risk = 2.0, float entry = 0.0, float stop_loss = 0.0) => math.round_to_mintick(calc_qty(portfolio,risk,entry,stop_loss) * entry)	// return value: currency amount 

// @function percentage trailing Stop Loss
//export pc_tsl(float portfolio = 10000, float risk = 0.02, float entry = 0.0, float average_true_range = 0.0) =>

// @function This function calculates the Risk Reward Ratio. Common values are between 1.5 and 2.0 and you should not go lower except for very few special cases.
// @param entry This is the limit-/market-price for the investment. In other words: The price per contract/share/unit you willing to buy or sell.
// @param stop_loss This is the limit-/market-price when to exit the trade, to minimize your losses.
// @param take_profit This is the limit-/market-price when to take profits.
// @returns float
export rrr(float entry = 0.0, float stop_loss = 0.0, float take_profit = 0.0) =>
	float reward = 0.0
	if take_profit > stop_loss
		reward := (take_profit - entry) / (entry - stop_loss)
	else if stop_loss > take_profit
		reward := (entry - take_profit) / (stop_loss - entry)
	reward

// @function Hoffman Trailing Stop Loss. This function returns trailing stop loss levels. 
// @param entry This is the price at which contracts/shares/units where bought/sold.
// @param take_profit This is target price of the contracts/shares/units.
// @returns tuple with three float values as pice. The tsl50% and tsl80% and tsl90%.
//export hoffman_tsl(float entry = 0.0, float take_profit = 0.0) =>
	//float ticks_total = take_profit > entry ? take_profit - entry : entry - take_profit
	//float ticks_tsl_50 = math.round_to_mintick(ticks_total * 0.5)
	//float ticks_tsl_80 = math.round_to_mintick(ticks_total * 0.8)
	//float ticks_tsl_90 = math.round_to_mintick(ticks_total * 0.9)
	//if take_profit > entry
		//[entry + ticks_tsl_50, entry + ticks_tsl_80, entry + ticks_tsl_90]
	//else
		//[entry - ticks_tsl_50, entry - ticks_tsl_80, entry - ticks_tsl_90]

// @function This function calculates the difference between price now and close price of the candle 'n' bars before that. If prices are very volatile but closed where they began, then this method would show zero volatility. Over many calculations, this method returns a reasonable measure of volatility, but will always be lower than those using the highs and lows.
// @param length The length is needed to determine how many candles/bars back should take into account.
// @returns float
export change_in_price(int length = 14) =>
	math.round_to_mintick(close - close[length]) // This code is of the book "Trading Systems and Methods."

// @function This function measures volatility over most recent candles, which could be used as an estimate of risk. It may also be effective as the basis for a stop-loss or take-profit, like the ATR but it ignores the frequency of directional changes within the time interval. In other words: The difference between the highest high and lowest low over 'n' bars.
// @param length The length is needed to determine how many candles/bars back should take into account.
// @returns float
export maximum_price_fluctuation(int length = 14) =>
	float highest_high = ta.highest(source = high, length = length)
	float lowest_low   = ta.lowest(source = low, length = length)
	math.round_to_mintick(highest_high - lowest_low) 	// This code is of the book "Trading Systems and Methods."

// @function This function measures volatility over most recent close prices. This is excellent for comparing volatility. It includes both frequency and magnitude. In other words: Sum of differences between second to last close price and last close price as absolute value for 'n' bars.
// @param length The length is needed to determine how many candles/bars back should take into account.
// @returns float
export absolute_price_changes(int length = 14) =>
	math.round_to_mintick(math.sum(math.abs(close[2] - close[1]), length - 1)) // This code is of the book "Trading Systems and Methods."

// @function This function measures volatility over most recent close prices. Its the standard deviation of close over the past 'n' periods, times the square root of the number of periods in a year.
// @param length The length is needed to determine how many candles/bars back should take into account.
// @returns float
export annualized_volatility(int length = 20) =>
	int trading_days = syminfo.type == "crypto" or syminfo.type == "forex" ? 365 : 252
	float resolution =
	 timeframe.isseconds ? 86400 * trading_days / timeframe.multiplier
	 : timeframe.isminutes ? 1440 * trading_days / timeframe.multiplier
	 : timeframe.isdaily ? trading_days / timeframe.multiplier
	 : timeframe.isweekly ? 52 / timeframe.multiplier
	 : timeframe.ismonthly ? 12 / timeframe.multiplier : na
	ta.stdev(math.log(close / close[1]), length) * math.sqrt(resolution)


	