Category: Finance

Anything related to finance.

  • Risk Measures: Value At Risk

    Risk Measures: Value At Risk

    Introduction

    This blog post introduces a new custom study to Sierra Chart which adds two popular risk metrics: value at risk (VaR) and conditional value at risk (CVaR). The study does a historical VaR and CVaR calculation given the length of the look back period and the confidence interval.

    If you are unfamiliar with what VaR or CVaR are, I will briefly describe them in the next section. If you are already familiar what these metrics are, feel free to skip to next section.

    An Introduction to VaR and CVaR

    VaR and CVaR are two common risk measures that help describe the distribution of losses from an asset or portfolio. Both measures require 2 inputs; the look back period (x) and the confidence interval (y).

    “VaR is the loss level we do not expected to be exceeded over the time horizon at the specified confidence interval” – GARP (2022)

    There are multiple different ways to calculate VaR such as historical simulation or monte carlo simulation. Historical simulation is done by sorting previous returns over period x and choosing the yth percentile return for VaR. CVaR is then the average of the remaining realizations that exceed the VaR level.

    Study Settings

    The study comes with a total of 5 sub graphs and 2 inputs.

    Inputs

    • Length (Bars): The look back period in chart bars
    • Confidence Interval (%): The confidence interval to run the analysis with

    Subgraphs

    • Change %: Percent change from today’s last price from yesterday’s last price
    • VAR %: The value at risk shown as a percentage
    • CVAR %: The conditional value at risk shown as a percentage
    • VAR $: The value at risk shown in dollars (VAR% * Last Price)
    • CVAR $: The conditional value at risk shown in dollars (CVAR% * Last Price)

    Interpretation

    VaR and CVaR ultimately exist to represent the risk of the specific asset that is being charted. Therefore, the most elementary interpretation is that the more negative the numbers, the higher the risk you should expect.

    Many investors might choose to look at standard deviation of returns or the price of an asset as the “risk,” but VaR and CVaR are often better representations. Furthermore, if given two identical investments with identical VaR but one has a higher CVaR, the one with the higher CVaR is considered riskier. This is because the larger CVaR means that when losses do exceed the VaR, they are larger in magnitude.

    The image to the right shows the difference between VaR calculations and the standard deviation of returns during the COVID-19 pandemic using a 2 year look back period. VaR is more responsive and gives investors a more logical way to think about risk than simply standard deviation of returns.

    Implementation

    The implementation of a historical VaR analysis is relatively simple and involves 2 main steps. The first step is to accumulate and sort the previous percent changes into an array. The next step is to calculate which item in the array corresponds with the given confidence interval.

    The code block to the right shows the implementation used in the study.

    One traditional feature of VaR that this implementation does not include is interpolation between data points. For example, in traditional VaR if there is a look back period of 150 with 99% confidence, the VaR will be the average between the 2nd and 3rd largest losses. In my implementation, the VaR is rounded to the nearest real occurrence (variable name VARIndex). This will produce minor difference in the calculation compared to interpolation, but these differences do not dramatically impact the interpret-ability or usefulness of the indicator. Furthermore, if you are using a look back period that evenly divides by (1-Confidence Interval), there is not interpolation required and therefore the answer is exact.

    struct RiskMetrics
    {
    	float VAR = 0.0f;
    	float ES = 0.0f;
    };
    
    RiskMetrics GetRiskMetrics(SCStudyGraphRef sc, SCSubgraphRef PercentChanges, int Length, float Percentile)
    {
    	RiskMetrics rm;
    
    	if (Percentile > 100.0f) return rm;
    
    	std::vector<float> Changes;
    	Changes.reserve(Length);
    
    	for (int i = sc.Index; i > sc.Index - Length; i--)
    		Changes.push_back(PercentChanges[i]);
    
    	std::sort(Changes.begin(), Changes.end());
    
    	if (Percentile == 100.0f)
    	{
    		rm.VAR = Changes[0];
    		rm.ES = Changes[0];
    		return rm;
    	}
    
    	float ItemWidth = 100.0f / static_cast<float>(Changes.size());
    
    	float Intermediate = (100.0f - Percentile) / ItemWidth;
    
    	uint32_t VARIndex = std::round(Intermediate);
    
    	rm.VAR = Changes[VARIndex];
    
    	for(int i = 0; i < VARIndex; i++)
    		rm.ES += Changes[i];
    
    	rm.ES /= static_cast<float>(VARIndex);
    
    	return rm;
    }
  • Algorithmic Trading Basics: Sierra Chart

    Algorithmic Trading Basics: Sierra Chart

    Introduction

    Welcome to my Sierra Chart Automated Trading Basics blog post. This blog post will cover how to submit orders and get position data using Sierra Chart’s ACSIL. This is not meant to serve as a complete tutorial, but rather a nice reference point for beginners. The full documentation for ACSIL can be found here.

    Sierra Chart Settings

    Before getting into the code, there are a few settings within Sierra Chart that need to be enabled to allow for automated trading.

    • Trade >> Auto Trading Enabled – Global
    • Trade >> Auto Trading Enabled – Chart
    • Trade >> Trade Simulation Mode

    Furthermore, there are additional settings that must be changed in order to submit orders to a live exchange. However, I will not cover those here and will leave that as an exercise to the reader. If you don’t want to figure that out, you probably shouldn’t be doing live automated trading. 😅

    Submitting Orders

    Sierra Chart handles orders through a structure they call SCNewOrder. You can populate this order structure with information relating to the order; such as quantity, order type, symbol, and more. For this example, we keep it simple with a single lot market order on the current symbol.

    	s_SCNewOrder OneLotMarket;
    	OneLotMarket.OrderQuantity = 1;
    	OneLotMarket.OrderType = SCT_ORDERTYPE_MARKET;
    	OneLotMarket.Symbol = sc.Symbol;

    Once you have populated your desired SCNewOrder you can pass it to the BuyEntry or SellEntry methods which will execute the trade as a new long or short position respectively. In order to close out of a trade, you pass the SCNewOrder structure to the BuyExit or SellExit methods.

    Checking Position

    Sierra Chart provides a method for retrieving current position data named GetTradePosition. It provides information about the current trade position including trade quantity, symbol, average price, and more. This information can and will be used for trading and risk management logic.

    Trading Logic

    The trading logic for this study is based on RSI and kept exceptionally simple. The study will enter a short position whenever RSI exceeds 80, enter a long when RSI is below 20, and close the trades whenever RSI has crossed 50.

    Code

    The full source code of the study has many more lines than shown in the code block to the right due to setting defaults and naming variables. To keep the code block as readable as possible, I excluded much of the unimportant “filler” lines. Feel free to view the entirety of the source code by downloading a copy using the link below.

    The code block clearly demonstrates how to create a new SCNewOrder, fill the order with information, and then act upon the order depending on other factors.

    SCSFExport scsf_RSITrader(SCStudyGraphRef sc)
    {
    	s_SCNewOrder OneLotMarket;
    	OneLotMarket.OrderQuantity = 1;
    	OneLotMarket.OrderType = SCT_ORDERTYPE_MARKET;
    	OneLotMarket.Symbol = sc.Symbol;
    
    	sc.RSI(sc.BaseDataIn[SC_LAST], RSISubgraph, RSIAvgType, RSILength);
    	auto& CurrentRSI = RSISubgraph[sc.Index];
    
    	s_SCPositionData PositionData;
    	sc.GetTradePosition(PositionData);
    
    	/* If position quantity is non-zero, handle position exit */
    	if (PositionData.PositionQuantity)
    	{
    		if (CurrentRSI > 50 && PositionData.PositionQuantity > 0)
    			sc.BuyExit(OneLotMarket);
    		else if (CurrentRSI < 50 && PositionData.PositionQuantity < 0)
    			sc.SellExit(OneLotMarket);
    
    		return;
    	}
    
    	/* Else, handle new positions */
    	if (CurrentRSI > SellThreshold)
    		sc.SellEntry(OneLotMarket);
    	else if (CurrentRSI < BuyThreshold)
    		sc.BuyEntry(OneLotMarket);
    }

    Final Result

    After building the file into a finished DLL and loading into Sierra Chart, this is what it looks like. The RSI is plotted as a purple solid line, while the buy/sell thresholds are represented as dotted green/red lines.

    Is the strategy any good?

    While this strategy is exceptionally simple, it provides interesting results. I ran a back test of the strategy with default study settings on 5 min NQU25 futures from April 2nd to September 18th. The strategy made 232 trades with an average profit per trade of 3.85 points for a total gain of 893.75 points. The winning percentage was 66.81% and the profit factor was 1.13.

    If you’d like to view the full statistics and trade log, the links to the data are below.

    Thank you for reading. I hope you learned something new.

  • Sierra Chart Study: ATR Percentage

    Sierra Chart Study: ATR Percentage

    Welcome to my first ever blog post. I will keep this one short and simple as a way for me to practice using the WordPress blog system.

    This post will include the source code for a Sierra Chart study which will show the current bar’s range as a percentage of a historical ATR. The length and moving average type of the historical ATR can be chosen through the inputs.

    I personally use this study intra-day as an alert for sudden increases in volatility. This is done by using Sierra Chart’s built in chart drawing alert feature.

    Code

    SCSFExport scsf_ATRPercentage(SCStudyGraphRef sc)
    {
    	auto& ATRSubgraph = sc.Subgraph[0];
    	auto& ATRPercentSubgraph = sc.Subgraph[1];
    	auto& ATRLengthInput = sc.Input[0];
    	auto& ATRTypeInput = sc.Input[1];
    
    	if (sc.SetDefaults)
    	{
    		sc.GraphName = "ATR Percentage";
    
    		sc.AutoLoop = 1;
    
    		ATRLengthInput.Name = "ATR Length";
    		ATRLengthInput.SetInt(14);
    
    		ATRTypeInput.Name = "ATR Type";
    		ATRTypeInput.SetMovAvgType(MOVAVGTYPE_SIMPLE);
    
    		ATRSubgraph.Name = "ATR";
    		ATRSubgraph.DrawStyle = DRAWSTYLE_IGNORE;
    
    		ATRPercentSubgraph.Name = "ATR Percentage";
    		ATRPercentSubgraph.DrawStyle = DRAWSTYLE_LINE;
    	}
    
    	auto Length = sc.Input[0].GetInt();
    	auto MovAvgType = sc.Input[1].GetMovAvgType();
    
    	sc.ATR(sc.BaseData, ATRSubgraph, Length, MovAvgType);
    
    	auto& CurrentBarHigh = sc.BaseData[SC_HIGH][sc.Index];
    	auto& CurrentBarLow = sc.BaseData[SC_LOW][sc.Index];
    	auto CurrentBarRange = CurrentBarHigh - CurrentBarLow;
    
    	ATRPercentSubgraph[sc.Index] = CurrentBarRange / ATRSubgraph[sc.Index];
    }