| 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;
}
}
}
}