public static double[] PriceDataFE_pred(Series <DateTime, double> input) { int shiftn = 0; var data = input.Shift(shiftn); var MA3 = data.Window(3).Select(x => x.Value.Mean()); var MA5 = data.Window(5).Select(x => x.Value.Mean()); var MA10 = data.Window(10).Select(x => x.Value.Mean()); var dataMA3 = (data / MA3).Select(x => Math.Log(x.Value)); var dataMA5 = (data / MA5).Select(x => Math.Log(x.Value)); var dataMA10 = (data / MA10).Select(x => Math.Log(x.Value)); var MA3MA5 = (MA3 / MA5).Select(x => Math.Log(x.Value)); var MA3MA10 = (MA3 / MA10).Select(x => Math.Log(x.Value)); var MA5MA10 = (MA5 / MA10).Select(x => Math.Log(x.Value)); var MMP3 = data.Window(3).Select(x => Math.Log(x.Value.Max() / x.Value.Min())); var MMP5 = data.Window(5).Select(x => Math.Log(x.Value.Max() / x.Value.Min())); var MMP10 = data.Window(10).Select(x => Math.Log(x.Value.Max() / x.Value.Min())); string dataMA3column = "PriceMA3" + Convert.ToString(shiftn); string dataMA5column = "PriceMA5" + Convert.ToString(shiftn); string dataMA10column = "PriceMA10" + Convert.ToString(shiftn); string MA3MA5column = "MA3MA5PRICE" + Convert.ToString(shiftn); string MA3MA10column = "MA3MA10PRICE" + Convert.ToString(shiftn); string MA5MA10column = "MA5MA10PRICE" + Convert.ToString(shiftn); string MMP3column = "MMP3" + Convert.ToString(shiftn); string MMP5column = "MMP5" + Convert.ToString(shiftn); string MMP10column = "MMP10" + Convert.ToString(shiftn); var Features = new FrameBuilder.Columns <DateTime, string> { { dataMA3column, dataMA3 }, { dataMA5column, dataMA5 }, { dataMA10column, dataMA10 }, { MA3MA5column, MA3MA5 }, { MA3MA10column, MA3MA10 }, { MA5MA10column, MA5MA10 }, { MMP3column, MMP3 }, { MMP5column, MMP5 }, { MMP10column, MMP10 } }.Frame; var row_length = Features.RowCount; var col_length = Features.ColumnCount; double[] delay_1 = Features.GetRowAt <double>(row_length - 1).Values.ToArray <double>(); double[] features_pred = new double[col_length]; for (int i = 0; i < col_length; i++) { features_pred[i] = delay_1[i]; } return(features_pred); }
public static void SumOfFrame() { var builder = new FrameBuilder.Columns <int, string>(); builder.Add("column1", new[] { 1, 2, 3, 4 }.ToOrdinalSeries()); builder.Add("column2", new[] { 1, 2, 3, 4 }.ToOrdinalSeries()); builder.Add("column3", new[] { 1, 2, 3, 4 }.ToOrdinalSeries()); builder.Add("column4", new[] { 1, 2, 3, 4 }.ToOrdinalSeries()); var df = builder.Frame; var sum = df.Sum().GetAllValues().ToArray(); Assert.AreEqual(10.0, sum[0].Value); Assert.AreEqual(10.0, sum[1].Value); }
public static void FramesOrderedAfterBuild() { var builder = new FrameBuilder.Columns <int, string>(); builder.Add("column1", new[] { 1, 2, 3, 4 }.ToOrdinalSeries()); builder.Add("column2", new[] { 1, 2, 3, 4 }.ToOrdinalSeries()); builder.Add("column3", new[] { 1, 2, 3, 4 }.ToOrdinalSeries()); builder.Add("column4", new[] { 1, 2, 3, 4 }.ToOrdinalSeries()); var frame = builder.Frame; Assert.AreEqual( new[] { "column1", "column2", "column3", "column4" }, frame.ColumnKeys.ToArray() ); }
public static Frame <DateTime, string> PriceDataFE(Series <DateTime, double> input) { int shiftn = 1; var data = input.Shift(shiftn); var MA3 = data.Window(3).Select(x => x.Value.Mean()); var MA5 = data.Window(5).Select(x => x.Value.Mean()); var MA10 = data.Window(10).Select(x => x.Value.Mean()); var dataMA3 = (data / MA3).Select(x => Math.Log(x.Value)); var dataMA5 = (data / MA5).Select(x => Math.Log(x.Value)); var dataMA10 = (data / MA10).Select(x => Math.Log(x.Value)); var MA3MA5 = (MA3 / MA5).Select(x => Math.Log(x.Value)); var MA3MA10 = (MA3 / MA10).Select(x => Math.Log(x.Value)); var MA5MA10 = (MA5 / MA10).Select(x => Math.Log(x.Value)); var MMP3 = data.Window(3).Select(x => Math.Log(x.Value.Max() / x.Value.Min())); var MMP5 = data.Window(5).Select(x => Math.Log(x.Value.Max() / x.Value.Min())); var MMP10 = data.Window(10).Select(x => Math.Log(x.Value.Max() / x.Value.Min())); string dataMA3column = "PriceMA3" + Convert.ToString(shiftn); string dataMA5column = "PriceMA5" + Convert.ToString(shiftn); string dataMA10column = "PriceMA10" + Convert.ToString(shiftn); string MA3MA5column = "MA3MA5PRICE" + Convert.ToString(shiftn); string MA3MA10column = "MA3MA10PRICE" + Convert.ToString(shiftn); string MA5MA10column = "MA5MA10PRICE" + Convert.ToString(shiftn); string MMP3column = "MMP3" + Convert.ToString(shiftn); string MMP5column = "MMP5" + Convert.ToString(shiftn); string MMP10column = "MMP10" + Convert.ToString(shiftn); var Features = new FrameBuilder.Columns <DateTime, string> { { dataMA3column, dataMA3 }, { dataMA5column, dataMA5 }, { dataMA10column, dataMA10 }, { MA3MA5column, MA3MA5 }, { MA3MA10column, MA3MA10 }, { MA5MA10column, MA5MA10 }, { MMP3column, MMP3 }, { MMP5column, MMP5 }, { MMP10column, MMP10 } }.Frame; return(Features); }
public static void CanGetColumnDynamically() { for (int i = 1; i <= 2; i++) // Run this twice, to check that instance references are right { var df = new FrameBuilder.Columns<int, string> { { "Test", new SeriesBuilder<int> { {1, 11.1}, {2,22.2} }.Series } }.Frame; dynamic dfd = df; Series<int, double> s0 = dfd.Test; dynamic s1 = dfd.Test; Assert.AreEqual(11.1, s0[1]); Assert.AreEqual(11.1, s1[1]); } }
public static void CanGetColumnDynamically() { for (int i = 1; i <= 2; i++) // Run this twice, to check that instance references are right { var df = new FrameBuilder.Columns <int, string> { { "Test", new SeriesBuilder <int> { { 1, 11.1 }, { 2, 22.2 } }.Series } }.Frame; dynamic dfd = df; Series <int, double> s0 = dfd.Test; dynamic s1 = dfd.Test; Assert.AreEqual(11.1, s0[1]); Assert.AreEqual(11.1, s1[1]); } }
public static void CanAddSeriesDynamically() { for (int i = 1; i <= 2; i++) // Run this twice, to check that instance references are right { var df = new FrameBuilder.Columns<int, string> { { "Test", new SeriesBuilder<int> { {1, 11.1}, {2,22.4} }.Series } }.Frame; dynamic dfd = df; dfd.Test1 = new[] { 1, 2 }; dfd.Test2 = df.GetColumn<double>("Test"); dfd.Test3 = new Dictionary<int, string> { { 1, "A" }, { 2, "B" } }; var row = df.Rows[2]; Assert.AreEqual(22.4, row["Test"]); Assert.AreEqual(2, row["Test1"]); Assert.AreEqual(22.4, row["Test2"]); Assert.AreEqual("B", ((KeyValuePair<int, string>)row["Test3"]).Value); } }
public static void CanAddSeriesDynamically() { for (int i = 1; i <= 2; i++) // Run this twice, to check that instance references are right { var df = new FrameBuilder.Columns <int, string> { { "Test", new SeriesBuilder <int> { { 1, 11.1 }, { 2, 22.4 } }.Series } }.Frame; dynamic dfd = df; dfd.Test1 = new[] { 1, 2 }; dfd.Test2 = df.GetColumn <double>("Test"); dfd.Test3 = new Dictionary <int, string> { { 1, "A" }, { 2, "B" } }; var row = df.Rows[2]; Assert.AreEqual(22.4, row["Test"]); Assert.AreEqual(2, row["Test1"]); Assert.AreEqual(22.4, row["Test2"]); Assert.AreEqual("B", ((KeyValuePair <int, string>)row["Test3"]).Value); } }
public static double[] Features_engineering_pred(Series <DateTime, double> input) { // Features engineering function for generating prediction input int shiftn = 0; var data = input.Shift(shiftn); var data2 = data.Select(x => Math.Pow(x.Value, 2)); var MA3 = data.Window(3).Select(x => x.Value.Mean()); var MA5 = data.Window(5).Select(x => x.Value.Mean()); var MA10 = data.Window(10).Select(x => x.Value.Mean()); var diffdataMA3 = (data / MA3).Select(x => x.Value - 1); var diffdataMA5 = (data / MA5).Select(x => x.Value - 1); var diffdataMA10 = (data / MA10).Select(x => x.Value - 1); var diffMA3MA5 = (MA3 / MA5).Select(x => x.Value - 1); var diffMA3MA10 = (MA3 / MA10).Select(x => x.Value - 1); var diffMA5MA10 = (MA5 / MA10).Select(x => x.Value - 1); var SD3 = data.Window(3).Select(x => x.Value.StdDev()); var SD5 = data.Window(5).Select(x => x.Value.StdDev()); var SD10 = data.Window(10).Select(x => x.Value.StdDev()); var RSI3 = data.Window(3).Select(x => RSI_func(x, 3)); var RSI5 = data.Window(5).Select(x => RSI_func(x, 5)); var RSI10 = data.Window(10).Select(x => RSI_func(x, 10)); var K3 = data.Window(3).Select(x => K_func(x, 3)); var K5 = data.Window(5).Select(x => K_func(x, 5)); var K10 = data.Window(10).Select(x => K_func(x, 10)); string Returncolumn = "Return" + Convert.ToString(shiftn); string Powercolumn = "Power" + Convert.ToString(shiftn); string MA3column = "MA3" + Convert.ToString(shiftn); string MA5column = "MA5" + Convert.ToString(shiftn); string MA10column = "MA10" + Convert.ToString(shiftn); string SD3column = "SD3" + Convert.ToString(shiftn); string SD5column = "SD5" + Convert.ToString(shiftn); string SD10column = "SD10" + Convert.ToString(shiftn); string CompareDataColumn1 = "dataMA3" + Convert.ToString(shiftn); string CompareDataColumn2 = "dataMA5" + Convert.ToString(shiftn); string CompareDataColumn3 = "dataMA10" + Convert.ToString(shiftn); string Compare1column = "MA3MA5" + Convert.ToString(shiftn); string Compare2column = "MA3MA10" + Convert.ToString(shiftn); string Compare3column = "MA5MA10" + Convert.ToString(shiftn); string RSI3column = "RSI3" + Convert.ToString(shiftn); string RSI5column = "RSI5" + Convert.ToString(shiftn); string RSI10column = "RSI10" + Convert.ToString(shiftn); string K3column = "K3" + Convert.ToString(shiftn); string K5column = "K5" + Convert.ToString(shiftn); string K10column = "K10" + Convert.ToString(shiftn); var Features = new FrameBuilder.Columns <DateTime, string> { { Returncolumn, data }, { Powercolumn, data2 }, { MA3column, MA3 }, { MA5column, MA5 }, { MA10column, MA10 }, { Compare1column, diffMA3MA5 }, { Compare2column, diffMA3MA10 }, { Compare3column, diffMA5MA10 }, { CompareDataColumn1, diffdataMA3 }, { CompareDataColumn2, diffdataMA5 }, { CompareDataColumn3, diffdataMA10 }, { SD3column, SD3 }, { SD5column, SD5 }, { SD10column, SD10 }, { RSI3column, RSI3 }, { RSI5column, RSI5 }, { RSI10column, RSI10 }, { K3column, K3 }, { K5column, K5 }, { K10column, K10 } }.Frame; var row_length = Features.RowCount; var col_length = Features.ColumnCount; double[] delay_1 = Features.GetRowAt <double>(row_length - 1).Values.ToArray <double>(); double[] delay_2 = Features.GetRowAt <double>(row_length - 2).Values.ToArray <double>(); double[] delay_3 = Features.GetRowAt <double>(row_length - 3).Values.ToArray <double>(); double[] features_pred = new double[col_length * 3]; for (int i = 0; i < col_length; i++) { features_pred[i] = delay_1[i]; } for (int i = 0; i < col_length; i++) { features_pred[i + col_length] = delay_2[i]; } for (int i = 0; i < col_length; i++) { features_pred[i + col_length * 2] = delay_3[i]; } return(features_pred); }
public static Frame <DateTime, string> Features_engineering(Series <DateTime, double> input, int shiftn) { //Features Engineering function for training machine learning var data = input.Shift(shiftn); var data2 = data.Select(x => Math.Pow(x.Value, 2)); var MA3 = data.Window(3).Select(x => x.Value.Mean()); var MA5 = data.Window(5).Select(x => x.Value.Mean()); var MA10 = data.Window(10).Select(x => x.Value.Mean()); var diffdataMA3 = (data / MA3).Select(x => x.Value - 1); var diffdataMA5 = (data / MA5).Select(x => x.Value - 1); var diffdataMA10 = (data / MA10).Select(x => x.Value - 1); var diffMA3MA5 = (MA3 / MA5).Select(x => x.Value - 1); var diffMA3MA10 = (MA3 / MA10).Select(x => x.Value - 1); var diffMA5MA10 = (MA5 / MA10).Select(x => x.Value - 1); var SD3 = data.Window(3).Select(x => x.Value.StdDev()); var SD5 = data.Window(5).Select(x => x.Value.StdDev()); var SD10 = data.Window(10).Select(x => x.Value.StdDev()); var RSI3 = data.Window(3).Select(x => RSI_func(x, 3)); var RSI5 = data.Window(5).Select(x => RSI_func(x, 5)); var RSI10 = data.Window(10).Select(x => RSI_func(x, 10)); var K3 = data.Window(3).Select(x => K_func(x, 3)); var K5 = data.Window(5).Select(x => K_func(x, 5)); var K10 = data.Window(10).Select(x => K_func(x, 10)); string Returncolumn = "Return" + Convert.ToString(shiftn); string Powercolumn = "Power" + Convert.ToString(shiftn); string MA3column = "MA3" + Convert.ToString(shiftn); string MA5column = "MA5" + Convert.ToString(shiftn); string MA10column = "MA10" + Convert.ToString(shiftn); string SD3column = "SD3" + Convert.ToString(shiftn); string SD5column = "SD5" + Convert.ToString(shiftn); string SD10column = "SD10" + Convert.ToString(shiftn); string CompareDataColumn1 = "dataMA3" + Convert.ToString(shiftn); string CompareDataColumn2 = "dataMA5" + Convert.ToString(shiftn); string CompareDataColumn3 = "dataMA10" + Convert.ToString(shiftn); string Compare1column = "MA3MA5" + Convert.ToString(shiftn); string Compare2column = "MA3MA10" + Convert.ToString(shiftn); string Compare3column = "MA5MA10" + Convert.ToString(shiftn); string RSI3column = "RSI3" + Convert.ToString(shiftn); string RSI5column = "RSI5" + Convert.ToString(shiftn); string RSI10column = "RSI10" + Convert.ToString(shiftn); string K3column = "K3" + Convert.ToString(shiftn); string K5column = "K5" + Convert.ToString(shiftn); string K10column = "K10" + Convert.ToString(shiftn); var Features = new FrameBuilder.Columns <DateTime, string> { { Returncolumn, data }, { Powercolumn, data2 }, { MA3column, MA3 }, { MA5column, MA5 }, { MA10column, MA10 }, { Compare1column, diffMA3MA5 }, { Compare2column, diffMA3MA10 }, { Compare3column, diffMA5MA10 }, { CompareDataColumn1, diffdataMA3 }, { CompareDataColumn2, diffdataMA5 }, { CompareDataColumn3, diffdataMA10 }, { SD3column, SD3 }, { SD5column, SD5 }, { SD10column, SD10 }, { RSI3column, RSI3 }, { RSI5column, RSI5 }, { RSI10column, RSI10 }, { K3column, K3 }, { K5column, K5 }, { K10column, K10 } }.Frame; return(Features); }
//------------------------------------------------------------------------------------------------ public Frame<DateTime, string> computeFuturesSpreads() //------------------------------------------------------------------------------------------------ { Log_.InfoFormat("Computing spreads..."); CombinedStatic = SpreadSeriesBuilder.combineFuturesAndBondStatic(BondStatic,FuturesStatic); var columns = FuturesPrices.Columns; FrameBuilder.Columns<DateTime, string> frameblder = new FrameBuilder.Columns<DateTime, string>(); // Iterate over columns for prices foreach (var col in FuturesPrices.ColumnKeys) { var series = columns[col].As<double>(); //series = series.Select(kvp => calcFuturesMeasure(SpreadMetric_, col, kvp.Value, kvp.Key)); var dte_idx = series.Keys.ToList(); SeriesBuilder<DateTime,double> sb = new SeriesBuilder<DateTime, double>(); Tuple<DateTime, double> prev = null; /* THIS ABSOLUTELY HAS TO BE IN ASCENDING ORDER */ dte_idx.Sort(); foreach(var dte in dte_idx) { var res = series.TryGet(dte); if (res.HasValue) { double price = res.Value; var staticRow = CombinedStatic.Rows.TryGet(col).ValueOrDefault; /* This section is to account for deficiencies in our database. */ // Quit if we don't have static if (staticRow == null) { sb.Add(dte, double.NaN); continue; } // Quit if we have a bad price if (price == 0.0) { sb.Add(dte, double.NaN); continue; } // Quit if contract isn't even trading var firstTradeDate = staticRow.GetAs<DateTime>("fut_first_trade_dt"); var lastTradeDate = staticRow.GetAs<DateTime>("last_tradeable_dt"); if (dte > lastTradeDate || dte < firstTradeDate) { sb.Add(dte, double.NaN); continue; } // Get price for AUD if (Conv_.Country == BondAnalytics.Country.AU) { DateTime maturity = TimeSeriesUtilities.LazySafeTryGetAs(staticRow, "Maturity", DateTime.MinValue); int tenor = (int)Math.Round((maturity - dte).Days / 365.25); price = BondAnalytics.CalcAUDFuturesContractValue(price, tenor); } // ASSUMPTION: Our DB seems to front fill by default. Skip days where no data is present /*if (prev != null && price == prev.Item2) { sb.Add(dte, double.NaN); continue; } */ double metric = calcFuturesMeasure(SpreadMetric_, col, price, dte, previous: prev); prev = new Tuple<DateTime, double>(dte, price); sb.Add(dte, metric); } else { sb.Add(dte, double.NaN); } } frameblder.Add(col, sb.Series); } var output = frameblder.Frame; Log_.InfoFormat("Complete:"); //output.Print(); return output.SortRowsByKey(); }
public static void FramesOrderedAfterBuild() { var builder = new FrameBuilder.Columns<int, string>(); builder.Add("column1", new[] { 1, 2, 3, 4 }.ToOrdinalSeries()); builder.Add("column2", new[] { 1, 2, 3, 4 }.ToOrdinalSeries()); builder.Add("column3", new[] { 1, 2, 3, 4 }.ToOrdinalSeries()); builder.Add("column4", new[] { 1, 2, 3, 4 }.ToOrdinalSeries()); var frame = builder.Frame; Assert.AreEqual( new[] { "column1", "column2", "column3", "column4" }, frame.ColumnKeys.ToArray() ); }
public static void BackTest(string Date, string Weeks) { /////////////////////////// /// /// Setting backtest object /// ////////////////////////// Backtest Mybacktest = new Backtest(); Backtest Mybacktest_adj = new Backtest(); // Initial the two backtest Mybacktest.Init(); Mybacktest_adj.Init(); /////////////////////////// /// /// Setting data container to store the information /// outside the for loop /// /////////////////////////// // setting netvalue lists for both standard strategy and dynamic strategy List <double> Hisc_netValue = new List <double>(); List <double> Adj_netValue = new List <double>(); // setting lists to store Fixed Income ETFs and Equity ETFs // we are holding during this trading week for the caculation of // Turnover Utility function List <string> ETFs_holding_FI = new List <string>(); List <string> ETFs_holding_Equ = new List <string>(); // setting matrix to store the trading history during this backtest string[][] trading_history_ETF = new string[Convert.ToInt64(Weeks)][]; double[][] trading_history_allocation = new double[Convert.ToInt64(Weeks)][]; double[][] ADJtrading_history_allocation = new double[Convert.ToInt64(Weeks)][]; // setting two variable drawdown and position ratio for the caculation // in Dynamic strategy, position ratio means the percentage of Fixed Income // ETFs we are currently holding double DrawDown = 0; double Position_ratio = 0.2; int FI_holding_weeks = 0; int Equ_holding_weeks = 0; double[] FI_holding_allocation = new double[5]; double[] Equ_holding_allocation = new double[5]; ////////////////////////////////// /// /// For loop backtest /// ///////////////////////////////// for (int i = 0; i < Convert.ToInt64(Weeks); i++) { // seting Datapreprocessing class for both Fixed Income ETFs and Equity ETFs DataPreProcessing pro_FI = new DataPreProcessing(); DataPreProcessing pro_Equ = new DataPreProcessing(); // caculate the date of today start from the 'Date' // which is given by backtest function var Today = DateTime.Parse(Date).AddDays(i * 7); // print the date we trained the model and trade Console.WriteLine("Date: {0}", Today.ToString()); // cleaning data use data preprocessing class pro_FI.Run(Today.ToString(), 112, "Fixed Income"); pro_Equ.Run(Today.ToString(), 112, "Equity"); // Set prediction vector double[] predictions_FI = new double[pro_FI.Trade_ETF.Count]; double[] predictions_Equ = new double[pro_Equ.Trade_ETF.Count]; // Set blend ETFs list to store the Top 10 etfs which is going to be // longed by the algorithm List <string> Blend_ETFs = new List <string>(); ///////////////////////////// /// /////// /// FI ETF prediction /////// /// /////// ///////////////////////////// for (int j = 0; j < pro_FI.Trade_ETF.Count; j++) { // Grab the data from the datapreprocessing object class var y = pro_FI.Target_List[j]; var fy = new FrameBuilder.Columns <DateTime, string> { { "Y", y } }.Frame; var data = pro_FI.Feature_List[j].Join(fy); var pred_Features = pro_FI.pred_Feature_List[j]; data.SaveCsv("dataset.csv"); // Training machine learning and predict var prediction = Learning.FitGBT(pred_Features); predictions_FI[j] = prediction; } // Get the minimum scores of top 5 ETF var hold_FI = PredRanking(predictions_FI, 5); // Get the namelist of top 5 ETF List <string> ETFs_FI = new List <string>(); for (int m = 0; m < pro_FI.Trade_ETF.Count; m++) { if (predictions_FI[m] >= hold_FI) { ETFs_FI.Add(pro_FI.Trade_ETF[m]); } } // Caculate the bid-ask spread cost if trade all 5 ETFs given by algorithm double[] FixedIncomeSpread = new double[5]; FixedIncomeSpread = GetBidAskSpread(ETFs_FI.ToArray()); // Cacualte the Unitility and decide if we should trade this week if (i == 0) { ETFs_holding_FI = ETFs_FI; } else { // get all prediction results of both holding etf and etfs which we may be going to trade double[] holding_pred = ETFname2Prediction(ETFs_holding_FI, predictions_FI, pro_FI); double[] long_pred = ETFname2Prediction(ETFs_FI, predictions_FI, pro_FI); // caculate the trade diff which is the utility of trading this week double trade_diff = long_pred.Sum() - holding_pred.Sum() - CaculateRebalanceCost(ETFs_FI, ETFs_holding_FI, FI_holding_allocation, pro_FI); // check if it is worth of trading if (trade_diff < 0) { // It is not worth of trading and ETFs portfolio will be same FI_holding_weeks += 1; ETFs_FI = ETFs_holding_FI; // setting spread equals to 0 because we are not going to trade this week FixedIncomeSpread = new double[] { 0, 0, 0, 0, 0 }; } else { FI_holding_weeks = 0; // It is worth of changing positions and trading this week ! // recaculate the spread costs because we may not going to trade all // ETFs which we are holding right now. for (int m = 0; m < 5; m++) { for (int n = 0; n < 5; n++) { if (ETFs_FI[m] == ETFs_holding_FI[n]) { FixedIncomeSpread[m] = 0; } else { continue; } } } // resetting the fixed income ETFs we are holding ETFs_holding_FI = ETFs_FI; } } Console.WriteLine("Long the following ETFs: "); // Store the Fixed Income ETFs namelist to blend ETFs list for (int n = 0; n < ETFs_FI.Count; n++) { Console.WriteLine(ETFs_FI[n]); Blend_ETFs.Add(ETFs_FI[n]); } /////////////////////////////////// /// /////// /// Equity ETF prediction /////// /// /////// /////////////////////////////////// for (int j = 0; j < pro_Equ.Trade_ETF.Count; j++) { // Run machine learning and predict next week for all ETFss var y = pro_Equ.Target_List[j]; var fy = new FrameBuilder.Columns <DateTime, string> { { "Y", y } }.Frame; var data = pro_Equ.Feature_List[j].Join(fy); var pred_Features = pro_Equ.pred_Feature_List[j]; data.SaveCsv("dataset.csv"); var prediction = Learning.FitGBT(pred_Features); predictions_Equ[j] = prediction; } List <string> ETFs_Equ = new List <string>(); // Find the min score of top 5 best ETFs var hold_Equ = PredRanking(predictions_Equ, 5); for (int m = 0; m < pro_Equ.Trade_ETF.Count; m++) { if (predictions_Equ[m] >= hold_Equ) { ETFs_Equ.Add(pro_Equ.Trade_ETF[m]); } } // caculate the bidAsk Spread double[] EquityBASpread = new double[5]; EquityBASpread = GetBidAskSpread(ETFs_Equ.ToArray()); if (i == 0) { ETFs_holding_Equ = ETFs_Equ; } else { double[] holding_pred = ETFname2Prediction(ETFs_holding_Equ, predictions_Equ, pro_Equ); double[] long_pred = ETFname2Prediction(ETFs_Equ, predictions_Equ, pro_Equ); // Caculate the Utility double trade_diff = long_pred.Sum() - holding_pred.Sum() - CaculateRebalanceCost(ETFs_Equ, ETFs_holding_Equ, Equ_holding_allocation, pro_Equ); // check if it is worth of trading this week if (trade_diff < 0) { Equ_holding_weeks += 1; ETFs_Equ = ETFs_holding_Equ; EquityBASpread = new double[] { 0, 0, 0, 0, 0 }; } else { // Recacluate the spread costs Equ_holding_weeks = 0; for (int m = 0; m < 5; m++) { for (int n = 0; n < 5; n++) { if (ETFs_Equ[m] == ETFs_holding_Equ[n]) { EquityBASpread[m] = 0; } else { continue; } } } ETFs_holding_Equ = ETFs_Equ; } } // Store the Equity ETFs we are going to long in Blend ETFs list for (int n = 0; n < ETFs_Equ.Count; n++) { Console.WriteLine(ETFs_Equ[n]); Blend_ETFs.Add(ETFs_Equ[n]); } // Caculate optimized allocations for both Fixed income and Equity ETFs ////////////////////////////// Console.WriteLine("Holding weeks for current Fixed Income ETFs is {0}", FI_holding_weeks); Console.WriteLine("Holding weeks for current Equity ETFs is {0}", Equ_holding_weeks); double[] AllocationFI = new double[5]; if (FI_holding_weeks == 0) { AllocationFI = PO.ETF2AllocationOwnOptim(ETFs_FI, pro_FI); FI_holding_allocation = AllocationFI; } else if (FI_holding_weeks < 15) { AllocationFI = FI_holding_allocation; } else { FI_holding_weeks = 0; AllocationFI = PO.ETF2AllocationOwnOptim(ETFs_FI, pro_FI); FI_holding_allocation = AllocationFI; } ////////////////////////////// double[] AllocationEqu = new double[5]; if (Equ_holding_weeks == 0) { AllocationEqu = PO.ETF2AllocationOwnOptim(ETFs_Equ, pro_Equ); Equ_holding_allocation = AllocationEqu; } else if (Equ_holding_weeks < 15) { AllocationEqu = Equ_holding_allocation; } else { Equ_holding_weeks = 0; AllocationEqu = PO.ETF2AllocationOwnOptim(ETFs_Equ, pro_Equ); Equ_holding_allocation = AllocationEqu; } ////////////////////////////// // Setting allocations which is an array to store allocations for strandard strategy double[] allocations = new double[10]; for (int fi = 0; fi < 5; fi++) { allocations[fi] = AllocationFI[fi] * 0.2; } for (int equ = 0; equ < 5; equ++) { allocations[equ + 5] = AllocationEqu[equ] * 0.8; } // Setting ALLOCATION which is an array to store allocations for strandard strategy double[] ALLOCATION = new double[10]; for (int fi = 0; fi < 5; fi++) { ALLOCATION[fi] = AllocationFI[fi] * Position_ratio; } for (int equ = 0; equ < 5; equ++) { ALLOCATION[equ + 5] = AllocationEqu[equ] * (1 - Position_ratio); } // Transform ETFs list to an array string[] ETFs = new string[10]; for (int etf = 0; etf < 10; etf++) { ETFs[etf] = Blend_ETFs[etf]; } // Storing the ETFs trading history and allocations trading_history_ETF[i] = new string[10]; trading_history_ETF[i] = ETFs; trading_history_allocation[i] = new double[10]; trading_history_allocation[i] = allocations; ADJtrading_history_allocation[i] = new double[10]; ADJtrading_history_allocation[i] = ALLOCATION; // Get the spread array for all ETFs double[] spread = new double[10]; Array.Copy(FixedIncomeSpread, spread, FixedIncomeSpread.Length); Array.Copy(EquityBASpread, 0, spread, FixedIncomeSpread.Length, EquityBASpread.Length); // Caculate the weighted spread for the adjustment in netvalue double weighted_spread = 0; for (int spreadItem = 0; spreadItem < 10; spreadItem++) { weighted_spread += allocations[spreadItem] * spread[spreadItem]; } // clearing the NetValue Hisc_netValue.Add(Mybacktest.Rebalance(Today, ETFs, allocations) * (1 - weighted_spread)); Adj_netValue.Add(Mybacktest_adj.Rebalance(Today, ETFs, ALLOCATION) * (1 - weighted_spread)); // Caculate the current drawdown and adjust the position ratio which is // the percentage for the fixed income ETFs if (i == 0) { DrawDown = 0; } else { DrawDown = 1 - Hisc_netValue.Last() / Hisc_netValue.Max(); } // Adjust the position ratio if (DrawDown > 0.1) { Position_ratio = 0.8; } else if (DrawDown > 0.08) { Position_ratio = 0.6; } else if (DrawDown > 0.05) { Position_ratio = 0.4; } else { Position_ratio = 0.2; } // Print out the current drawdown and position ratio. Console.WriteLine("Current drawdown is: {0}", DrawDown); Console.WriteLine("Fixed Income has been adjusted to: {0} %", Position_ratio * 100); } // Result analysis for NetValue ///////////////////// /// /// Backtest Metrics of Strandard Strategy /// //////////////////// var StrategyNetValue = Hisc_netValue.ToArray(); double MaxDD = 0; for (int i = 1; i < StrategyNetValue.Length; i++) { var MaxNetValue = StrategyNetValue.Take(i).Max(); double drawdown = 1 - StrategyNetValue[i] / MaxNetValue; if (drawdown > MaxDD) { MaxDD = drawdown; } } Console.WriteLine("Maximum drawdown of This Strategy is: {0}", MaxDD); var AnnualReturn = Math.Log(StrategyNetValue.Last()) / (Convert.ToDouble(Weeks) / 50); Console.WriteLine("Annual Return of This Strategy is: {0}", AnnualReturn); var StrategyReturn = NetValue2Return(StrategyNetValue); Console.WriteLine("Standard Deviation of This Strategy is: {0}", Statistics.StandardDeviation(StrategyReturn)); double[] BTmetrics = new double[3]; BTmetrics[0] = AnnualReturn; BTmetrics[1] = MaxDD; BTmetrics[2] = Statistics.StandardDeviation(StrategyReturn) * Math.Sqrt(50); // Result analysis for AdjNetValue ///////////////////// /// /// Backtest Metrics of Dynamic Strategy /// ///////////////////// var ADJStrategyNetValue = Adj_netValue.ToArray(); double ADJMaxDD = 0; for (int i = 1; i < ADJStrategyNetValue.Length; i++) { var MaxNetValue = ADJStrategyNetValue.Take(i).Max(); double drawdown = 1 - ADJStrategyNetValue[i] / MaxNetValue; if (drawdown > ADJMaxDD) { ADJMaxDD = drawdown; } } Console.WriteLine("Maximum drawdown of ADJ Strategy is: {0}", ADJMaxDD); var ADJAnnualReturn = Math.Log(ADJStrategyNetValue.Last()) / (Convert.ToDouble(Weeks) / 50); Console.WriteLine("Annual Return of ADJ Strategy is: {0}", ADJAnnualReturn); var ADJStrategyReturn = NetValue2Return(ADJStrategyNetValue); Console.WriteLine("Standard Deviation of This Strategy is: {0}", Statistics.StandardDeviation(ADJStrategyReturn)); double[] ADJBTmetrics = new double[3]; ADJBTmetrics[0] = ADJAnnualReturn; ADJBTmetrics[1] = ADJMaxDD; ADJBTmetrics[2] = Statistics.StandardDeviation(ADJStrategyReturn) * Math.Sqrt(50); // Output all results to CSV // Without position adjustment SaveArrayAsCSV_(trading_history_allocation, "StrandardTradingHistoryAllocation.csv"); SaveArrayAsCSV(BTmetrics, "StandardBacktestMetrics.csv"); SaveArrayAsCSV(StrategyNetValue, "StandardNet_value.csv"); // With position adjustmnet SaveArrayAsCSV_(ADJtrading_history_allocation, "DynamicTradingHistoryAllocation.csv"); SaveArrayAsCSV(ADJBTmetrics, "DynamicBacktestMetrics.csv"); SaveArrayAsCSV(ADJStrategyNetValue, "DynamicNetValue.csv"); SaveArrayAsCSV_ <string>(trading_history_ETF, "ETFTradingHistoryforALL.csv"); Console.ReadKey(); }