Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
-2.688
Tracking Error
0.134
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
/*
	This program was developed by Quantify and is property of Mario Sarli
    Usage and marketing of this program is permitted.
    
    Quantify Developer(s): Conor Flynn
    Date Created: 07/13/2021
    Client: Mario Sarli
    Client ID: 341994651
    
    If you find a bug or an inconsistantcy please contact your assigned developer.
    Contact: cflynn@quantify-co.com
    
    To request a new copy of your program please contact support:
    Contact: support@quantify-co.com
    
    Note: Client ID is required for client verification upon requesting a new copy
*/

namespace QuantConnect.Algorithm.CSharp
{
    public class Main : QCAlgorithm
    {
    	// BACKTESTING PARAMETERS
    	// =================================================================================================================
    	
    	// general settings:
    	
    	// set starting cash
    	private int starting_cash = 100000;
    	
    	// backtesting start date time:
    	// date setting variables
    	private int start_year = 2021;
    	private int start_month = 1;
    	private int start_day = 1;
    	
    	// backtesting end date time:
    	// determines whether there is a specified end date
    	// if false it will go to the current date (if 'true' it will go to the specified date)
    	private bool enable_end_date = false;
    	// date setting variables
    	private int end_year = 2020;
    	private int end_month = 1;
    	private int end_day = 1;
    	
    	
    	// universe settings:
    	
    	// data update resolution
    	// changes how often the data updates and algorithm looks for entry
    	// determines how often the function OnData runs
    	// list of resolutions:
    	// Resolution.Tick; Resolution.Second; Resolution.Minute; Resolution.Hour; Resolution.Daily
    	private readonly Resolution resolution = Resolution.Second;
    	
    	// stock list
    	// list of stocks you want in the universe
    	// used in manual selection of universe
    	// set selection_type = false for activation
    	private readonly String[] manual_universe = new String[]{"SPY", "AAPL"};
    	
    	
    	// indicator settings:
    	
    	// length of the SMA for the base line (line 2, init line 4, 5)
    	private readonly int length_base = 50;
    	
    	// base calculation type: (line 4, 5)
    	// 1: OHLC4
    	// 2: (H+L) / 2
    	private static readonly int calculation_base = 1;
    	
    	// length of the SMA for the space line: (line 2, init line 21)
    	private readonly int length_space = 50;
    	
    	// space calculation type: (line 21)
    	// 1: (H-L)
    	// 2: abs(C-O)
    	private static readonly int calculation_space = 1;
    	
    	// space factor: (line 24)
    	private static readonly decimal factor_space = 1.0m;
    	
    	// number of spacers from the base line (default 10)
    	private readonly int count_space = 10;
    	
    	// =================================================================================================================
		
		// creates new universe variable setting
		private List<StockData> universe = new List<StockData>();
		
		// security changes variable
		private SecurityChanges securityChanges = SecurityChanges.None;
		
        public override void Initialize()
        {
        	// set start date
            SetStartDate(start_year, start_month, start_day);
            // set end date
            if(enable_end_date)
            	SetEndDate(end_year, end_month, end_day);
            // set starting cash
            SetCash(starting_cash);
            
            // add all equities into the universe
            foreach(string s in manual_universe) {
	            AddEquity(s, resolution);
	            
	            // create StockData variable for security
            	StockData sd = new StockData();
            	sd.algorithm = this;
            	sd.ticker = s;
            	sd.sma_base = new SimpleMovingAverage(length_base);
            	sd.sma_space = new SimpleMovingAverage(length_space);
            	sd.pos_space = new decimal[count_space];
            	sd.neg_space = new decimal[count_space];
            	// add stockdata to universe
            	universe.Add(sd);
            }
        }

        // OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        // Slice object keyed by symbol containing the stock data
        public override void OnData(Slice data) {
        	// loops through each stock in universe
        	foreach(StockData sd in universe) {
        		// update values
        		sd.update();
        		
        		// if data is not ready then skip
        		if(!sd.IsReady)
        			continue;
        		
        		// if long check for short
        		if(sd.direction == 1 && sd.IsShort()) {
        			// enter short
        		}
        		
        		// if short check for long
        		else if(sd.direction == -1 && sd.IsLong()) {
        			// enter long
        		}
        		
        		// if not in position wait for either
        		else if(sd.direction == 0) {
        			if(sd.IsLong()) {
        				// enter long
        			} else if(sd.IsShort()) {
        				// enter short
        			}
        		}
        	}
        }
		
		// default class containing all ticker information
		public class StockData {
			// QCAlgorithm variable
			public QCAlgorithm algorithm;
			// stock ticker
			public string ticker = "";
			// simple moving average baseline (line 7)
			public SimpleMovingAverage sma_base;
			// spacing period (line 21)
			public SimpleMovingAverage sma_space;
			// stores all line space calculations
			public decimal[] pos_space;
			public decimal[] neg_space;
			// stores the prior and current index
			public int index = -10000;
			private int prev_index = -10000;
			// variable determining long, short, or null (1, -1, 0):
			public int direction = 0;
			
			// determines if data is ready
			public bool IsReady => sma_base.IsReady && sma_space.IsReady && index != -10000 && prev_index != -10000;
			
			// updates spacing calculations
			public void update() {
				// define security object
				Security sym = algorithm.Securities[ticker];
				
				// Update SMAs
				UpdateSMA(sym);
				
				// Update Spacing
				UpdateSpacing(sym);
			}
			
			// updates the SMAs used for calculation
			private void UpdateSMA(Security sym) {
				// update the base sma
				decimal price;
				if(Main.calculation_base == 1) {
					// OHLC4
					price = (sym.Open + sym.High + sym.Low + sym.Close) / 4;
				} else if(Main.calculation_base == 2) {
					// (H+L) / 2
					price = (sym.High + sym.Low) / 2;
				} else {
					// invalid value
					algorithm.Error("INVALID <calculation_base> VALUE");
					price = -1.0m;
				}
				// push to object
				sma_base.Update(algorithm.Time, price);
				
				// update the space sma
				if(Main.calculation_space == 1) {
					// (H-L)
					price = (sym.High - sym.Low);
				} else if(Main.calculation_space == 2) {
					// abs(C-O)
					price = Math.Abs(sym.Close - sym.Open);
				} else {
					// invalid value
					algorithm.Error("INVALID <calculation_space> VALUE");
					price = -1.0m;
				}
				// push to object
				sma_space.Update(algorithm.Time, price);
			}
			
			// updates the indicies of the spacing arrays
			private void UpdateSpacing(Security sym) {
				// determine if above or below base
				if(sym.Price > sma_space) {
					
					// set 0 as base
					pos_space[0] = sma_space;
					
					// update spacing and determine where the price is at
					for(int i = 1; i < pos_space.Count(); i++) {
						pos_space[i] = sma_base + (sma_space * i * Main.factor_space);
						
						// if between prior index and current then set accoring
						if(sym.Price > pos_space[i - 1] && sym.Price < pos_space[i]) {
							prev_index = index;
							index = i;
						}
					}
					
				} else if(sym.Price < sma_space) {
					
					// set 0 as base
					neg_space[0] = sma_space;
					
					// update spacing and determine where the price is at
					for(int i = 1; i < neg_space.Count(); i++) {
						neg_space[i] = sma_base - (sma_space * i * Main.factor_space);
						
						// if between prior index and current then set accoring
						if(sym.Price < neg_space[i - 1] && sym.Price > neg_space[i]) {
							prev_index = index;
							index = i;
						}
					}
					
				} else {
					index = 0;
				}
			}
			
			// determines if the algorithm crossed long
			public bool IsLong() {
				return index > prev_index;
			}
			
			// determine if the algorithm crossed short
			public bool IsShort() {
				return index < prev_index;
			}
			
		}
    }
}