Your interactive trading laboratory!
 • 
19 users online

Adaptive Asset Allocation

I am sorry to ask you so many questions, but please tell me how to convert this wealth-lab code to QS 194.

https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2328254

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;
using WealthLab.Rules;
using Community.Indicators;

namespace WealthLab.Strategies
{   
	#region Helper classes
  
	public class RankHolder
	{
		public string symbol;
		public double val;
		public double rank;
	}
  
	public class MomHolder : RankHolder
	{
		public MomHolder( string symbol, double val )
		{
			this.symbol = symbol;
			this.val = val;
		}
	}
  
	public class VolHolder : RankHolder
	{
		public VolHolder( string symbol, double val )
		{
			this.symbol = symbol;
			this.val = val;
		}
	}
  
	public class CorrHolder : RankHolder
	{
		public CorrHolder( string symbol, double val )
		{
			this.symbol = symbol;
			this.val = val;
		}
	}
  
	public class HolderContainer
	{
		public MomHolder momHolder;
		public VolHolder volHolder;
		public CorrHolder corrHolder;
    
	}
  
	#endregion Helper classes
  
  /******************** 
0 - 0.32 0%
0.33 - 0.49 50%
0.50 - 0.67 67%
0.68 - 1.0 100%
*********************/
  
	public class CombinedRanking : WealthScript, IComparer<RankHolder>, IComparer<MomHolder>, IComparer<VolHolder>, IComparer<CorrHolder>
	{

		StrategyParameter numberOfSymbols;
		StrategyParameter momPeriod_;
		StrategyParameter volPeriod_;
		StrategyParameter corrPeriod_;
		StrategyParameter momWeight_;
		StrategyParameter volWeight_;
		StrategyParameter corrWeight_;
		public CombinedRanking()
		{
			numberOfSymbols = CreateParameter("n Symbols", 3, 2, 5, 1);
			momPeriod_ = CreateParameter("Mom Period", 4, 4, 4, -1);
			volPeriod_ = CreateParameter("Vol Period", 4, 4, 4, -1);
			corrPeriod_ = CreateParameter("Corr Period", 4, 4, 4, -1);
			momWeight_ = CreateParameter("Mom Weight", 1, 1, 1, -1);
			volWeight_ = CreateParameter("Vol Weight", 0.5, 0.5, 0.5, -1);
			corrWeight_ = CreateParameter("Corr Weight", 0.5, 0.5, 0.5, -1);
      
       
		}  
     
		/* Add this BuyAtMarket method and nothing else needs to be changed */
		// It uses a limit order that executes at the opening price so that the basis price is the same as the execution price
		Position BuyAtClose(int n, string sigName = "")
		{
			if (n >= Bars.Count)
				return base.BuyAtClose(n, sigName);   // create market order alert
			else
				return BuyAtLimit(n, Close[n], sigName);
		}
		
		protected override void Execute()
		{
     
			//Clear cached symbol list so they can be re-requested with synchronization
			ClearExternalSymbols();
			int number = numberOfSymbols.ValueInt;
			int momPeriod = momPeriod_.ValueInt;
			int volPeriod = volPeriod_.ValueInt;
			int corrPeriod = corrPeriod_.ValueInt;
			double wM = momWeight_.Value;
			double wV = volWeight_.Value;
			double wC = corrWeight_.Value;
       
            
			//Execute rotation strategy
			Dictionary<string, HolderContainer> holders = new Dictionary<string, HolderContainer>();
			List<MomHolder> listMom = new List<MomHolder>();
			List<VolHolder> listVol = new List<VolHolder>();
			List<CorrHolder> listCorr = new List<CorrHolder>();
			List<RankHolder> list = new List<RankHolder>(); // the combined list
        
        
        
			for(int bar = Math.Max( momPeriod, Math.Max(volPeriod, corrPeriod)); bar < Bars.Count; bar++)
			{
				listMom.Clear();
				listVol.Clear();
				listCorr.Clear();
				list.Clear();
				holders.Clear();
           
				foreach(string symbol in DataSetSymbols)
				{
					SetContext(symbol, true);
					HolderContainer hc = new HolderContainer();
					MomHolder mh = null;
					VolHolder vh = null;
					CorrHolder ch = null;
					if (Bars.FirstActualBar < bar)
					{
						SetScaleMonthly();
						DataSeries  mom = ROC.Series(Bars.Close, momPeriod);
						RestoreScale();
						mom = Synchronize(mom);
						mh =  new MomHolder( symbol, mom[bar]);
						listMom.Add(mh);
						hc.momHolder = mh;
                 
						DataSeries vol = -1 * StdDev.Series( ROC.Series( Bars.Close, 1 ), volPeriod * 21, StdDevCalculation.Population  ) * Math.Sqrt(252); // lowest is best
						vh = new VolHolder( symbol, vol[bar]);
						listVol.Add(vh);
						hc.volHolder = vh;
                 
						ch = new CorrHolder( symbol, -1 * CalcPfC(Bars.Close, corrPeriod * 21, bar));
						listCorr.Add(ch);
						hc.corrHolder = ch;
                 
						holders.Add(symbol, hc);
                 
					}
                 
					RestoreContext();
				}
        
				listMom.Sort(this); // highest is best
				listVol.Sort(this); // lowest is best
				listCorr.Sort(this); // lowest is best
               
         
				// Generate Momentum Ranks
				for (int i=0; i < listMom.Count; i++)
				{
					listMom[i].rank = i + 1;
				}
         
           
				// Generate Volatility Ranks
				for (int i=0; i < listVol.Count; i++)
				{
					listVol[i].rank = i + 1;
				}         
         
     
				// Generate Correlation Ranks
				for (int i=0; i < listCorr.Count; i++)
				{
					listCorr[i].rank = i + 1;
				}   
                  
        
				// Iterate through holder dictionary, determining MVC rank for each symbol and creating list of MVC RankHolders
				foreach(KeyValuePair<string, HolderContainer> entry in holders)
				{
					RankHolder rh = new RankHolder();
					rh.symbol = entry.Key;
					HolderContainer hc = entry.Value;
           
           
					rh.val = (wM + 0.001) * hc.momHolder.rank  + wV * hc.volHolder.rank + wC * hc.corrHolder.rank;
					list.Add(rh);
              
				}
        
				list.Sort(this); // lowest is best 
           
        
         
				// Generate MVC Ranks
				/*
				for (int i=0; i < list.Count; i++)
				{
				list[i].rank = i + 1;
				}          
				*/
        
           
				//keep top number (3 is initial default) only
				for(int i = list.Count - 1; i >= number; i--)
					list.RemoveAt(i);
           
        
				//Filter/Remove the ones with Absolute Momentum < 0
				for (int i=0; i < list.Count; i++)
				{
					RankHolder rh = list[i];
					if (holders[rh.symbol].momHolder.val < 0)
					{
						list.RemoveAt(i);
					}
				}
              
           
				//Close positions that are not in the new lowest 3
				for(int pos = ActivePositions.Count - 1; pos >= 0; pos--)
				{
					Position p = ActivePositions[pos];
					bool keepPosition = false;
					foreach(RankHolder holder in list)
						if (holder.symbol == p.Bars.Symbol)
						{
							keepPosition = true;
							break;
						}
					if (
						(!keepPosition)  && 
						DateRules.IsLastTradingDayOfMonth(Bars.Date[bar]) 
						)
						SellAtClose(bar, p, "Rotation");           
				}
              
				double posPriority = (double) 1/number; 
				PrintDebug("Priority: "+ posPriority);
				PrintDebug("Count: "+ list.Count);
				PrintDebug("Number: "+ number);
				double cashPriority = 1 - (list.Count * posPriority);
   
				//Buy new positions
				foreach(RankHolder holder in list)
				{
					bool buyPosition = true;
					foreach(Position p in ActivePositions)
						if (p.Bars.Symbol == holder.symbol)
						{
							buyPosition = false;
							break;
						}
					if (
						(buyPosition) &&
						(DateRules.IsLastTradingDayOfMonth(Bars.Date[bar]))
						)
					{
						SetContext(holder.symbol, true);
						if (BuyAtClose(bar, "Rotation") != null)
						{
							LastPosition.Priority =  posPriority;
						}
						RestoreContext();
					}
				}
			}
			PrintStatusBar("Strategy completed!");
		}
     
		public double CalcPfC( DataSeries close, int length, int bar )
		{
			// This function takes a symbol and a list of symbols 
			// and calculates the average correlation of the
			// symbols TS to the other symbols TS's (TS:TimeSeries)
  
			double corSum = 0;
			int j=0;
     
        
			foreach(string ticker in DataSetSymbols)
			{
           
				Bars tickerBars = GetExternalSymbol(ticker, true);
				corSum  = corSum + Correlation.Series(tickerBars.Close , close, length )[bar];
				j++;
           
           
           /*
           SetContext(ticker, true);
            if (Bars.FirstActualBar < bar)
           {
                corSum  = corSum + Correlation.Series(Bars.Close , close, length )[bar];   
           }
           RestoreContext();
           j++;
               */  
			}
			// take out the diagonal of the correlation matrix and average
			return (corSum - 1)/ (j -1);

        
        
		}
     
    
     
		#region IComparer implementation
     
		public int Compare(RankHolder item1, RankHolder item2)
		{
			return item1.val.CompareTo(item2.val); // ascending -> worst - best
		}
     
		public int Compare(MomHolder item1, MomHolder item2)
		{
			return item2.val.CompareTo(item1.val); // descending -> best - worst
		}
    
		public int Compare(VolHolder item1, VolHolder item2)
		{
			return item2.val.CompareTo(item1.val); // descending -> best - worst
		}
    
		public int Compare(CorrHolder item1, CorrHolder item2)
		{
			return item2.val.CompareTo(item1.val); // descending -> best - worst
		}
     
		#endregion
	}
}
Attachment

Cancel

Responses

I know not Wealth Lab code, but I've always been interested in this family of algorithmic approaches, and I think this would give me a chance to try my hand. I'm kinda busy right now, but in stages perhaps I can try this, and perhaps others will chime in. What symbols do you want to test for the ten asset classes they use?

I know not Wealth Lab code, but I've always been interested in this family of algorithmic approaches, and I think this would give me a chance to try my hand. I'm kinda busy right now, but in stages perhaps I can try this, and perhaps others will chime in. What symbols do you want to test for the ten asset classes they use?

Hi bitfool,

Thank you for your reply. The following ETFs are targeted for investment in the paper.

SPY, EFA, EWJ, EEM, IYR, RWX, IEF, TLT, DBC, GLD

Momentum strategies such as adaptive asset allocation do not correlate with short term reversal strategies such as RSI Rotation, so I believe that combining them will increase sharpe ratio.

Hi bitfool, Thank you for your reply. The following ETFs are targeted for investment in the paper. SPY, EFA, EWJ, EEM, IYR, RWX, IEF, TLT, DBC, GLD Momentum strategies such as adaptive asset allocation do not correlate with short term reversal strategies such as RSI Rotation, so I believe that combining them will increase sharpe ratio.
Forum Tips

Please sign in if you want to participate in our forum.

Our forum uses Markdown syntax to format posts.

To embed code snippets, enclose them in [CODE][/CODE] tags.