[Quantproject-developers] QuantProject/b7_Scripts/TechnicalAnalysisTesting/Oscillators/FixedLevelOs
Brought to you by:
glauco_1
|
From: Marco M. <mi...@us...> - 2006-09-17 21:24:57
|
Update of /cvsroot/quantproject/QuantProject/b7_Scripts/TechnicalAnalysisTesting/Oscillators/FixedLevelOscillators/PortfolioValueOscillator In directory sc8-pr-cvs7.sourceforge.net:/tmp/cvs-serv25928/b7_Scripts/TechnicalAnalysisTesting/Oscillators/FixedLevelOscillators/PortfolioValueOscillator Added Files: RunPVO.cs GenomeMeaningPVO.cs GenomeManagerPVO.cs EndOfDayTimerHandlerPVO.cs Log Message: Added Portfolio Value Oscillator strategy. This strategy is similar to the strategy based on the popular technical RSI indicator (Relative Strength Index). --- NEW FILE: GenomeManagerPVO.cs --- /* QuantProject - Quantitative Finance Library GenomeManagerPVO.cs Copyright (C) 2003 Marco Milletti This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ using System; using System.Data; using System.Collections; using QuantProject.ADT; using QuantProject.ADT.Statistics; using QuantProject.ADT.Optimizing.Genetic; using QuantProject.Data; using QuantProject.Data.DataTables; using QuantProject.Scripts.TickerSelectionTesting.EfficientPortfolios; namespace QuantProject.Scripts.TechnicalAnalysisTesting.Oscillators.FixedLevelOscillators.PortfolioValueOscillator { /// <summary> /// Implements what needed to use the Genetic Optimizer /// for finding the portfolio that best suites /// the Portfolio Value Oscillator strategy /// </summary> [Serializable] public class GenomeManagerPVO : GenomeManagerForEfficientPortfolio { private int minLevelForOversoldThreshold; private int maxLevelForOversoldThreshold; private int minLevelForOverboughtThreshold; private int maxLevelForOverboughtThreshold; private int divisorForThresholdComputation; private double currentOversoldThreshold = 0.0; private double currentOverboughtThreshold = 0.0; private int numDaysForOscillatingPeriod; private double[] portfolioValues;//the values for each unit, invested //at the beginning of the optimization period, //throughout the period itself private void genomeManagerPVO_checkParametersForThresholdComputation() { if(this.maxLevelForOverboughtThreshold < this.minLevelForOverboughtThreshold || this.maxLevelForOversoldThreshold < this.minLevelForOversoldThreshold || this.divisorForThresholdComputation < this.maxLevelForOverboughtThreshold || this.divisorForThresholdComputation < this.maxLevelForOversoldThreshold) throw new Exception("Bad parameters for threshold computation!"); } public GenomeManagerPVO(DataTable setOfInitialTickers, DateTime firstQuoteDate, DateTime lastQuoteDate, int numberOfTickersInPortfolio, int numDaysForOscillatingPeriod, int minLevelForOversoldThreshold, int maxLevelForOversoldThreshold, int minLevelForOverboughtThreshold, int maxLevelForOverboughtThreshold, int divisorForThresholdComputation, PortfolioType portfolioType) : base(setOfInitialTickers, firstQuoteDate, lastQuoteDate, numberOfTickersInPortfolio, 0.0, portfolioType) { this.numDaysForOscillatingPeriod = numDaysForOscillatingPeriod; this.minLevelForOversoldThreshold = minLevelForOversoldThreshold; this.maxLevelForOversoldThreshold = maxLevelForOversoldThreshold; this.minLevelForOverboughtThreshold = minLevelForOverboughtThreshold; this.maxLevelForOverboughtThreshold = maxLevelForOverboughtThreshold; this.divisorForThresholdComputation = divisorForThresholdComputation; this.genomeManagerPVO_checkParametersForThresholdComputation(); this.retrieveData(); } public override int GenomeSize { get{return this.genomeSize + 2;} //two initial genes are for oversold and overbought thresholds } public override int GetMinValueForGenes(int genePosition) { int returnValue; switch (genePosition) { case 0 ://gene for oversold threshold returnValue = this.minLevelForOversoldThreshold; break; case 1 ://gene for overbought threshold returnValue = this.minLevelForOverboughtThreshold; break; default://gene for ticker returnValue = - this.originalNumOfTickers; break; } return returnValue; } public override int GetMaxValueForGenes(int genePosition) { int returnValue; switch (genePosition) { case 0 ://gene for oversold threshold returnValue = this.maxLevelForOversoldThreshold; break; case 1 ://gene for overbought threshold returnValue = this.maxLevelForOverboughtThreshold; break; default://gene for ticker returnValue = this.originalNumOfTickers - 1; break; } return returnValue; } protected override float[] getArrayOfRatesOfReturn(string ticker) { float[] returnValue = null; Quotes tickerQuotes = new Quotes(ticker, this.firstQuoteDate, this.lastQuoteDate); returnValue = QuantProject.ADT.ExtendedDataTable.GetArrayOfFloatFromColumn(tickerQuotes, Quotes.AdjustedCloseToCloseRatio); for(int i = 0; i<returnValue.Length; i++) returnValue[i] = returnValue[i] - 1.0f; this.numberOfExaminedReturns = returnValue.Length; return returnValue; } //starting from this.numDaysForOscillatingPeriod day, //it computes for each day ahead the value of the //portfolio opened numDaysForOscillatingPeriod days ago private double[] getPortfolioMovingValues() { double[] returnValue = new double[this.portfolioRatesOfReturn.Length]; double[] valuesInOscillatingPeriod = new double[this.numDaysForOscillatingPeriod]; valuesInOscillatingPeriod[0] = 1.0; for(int i = this.numDaysForOscillatingPeriod; i<returnValue.Length; i++) { for(int j = 1; j < this.numDaysForOscillatingPeriod; j++) valuesInOscillatingPeriod[j] = valuesInOscillatingPeriod[j - 1] + valuesInOscillatingPeriod[j - 1] * this.portfolioRatesOfReturn[i-this.numDaysForOscillatingPeriod+j]; returnValue[i-1] = valuesInOscillatingPeriod[this.numDaysForOscillatingPeriod -1]; } return returnValue; } private void getFitnessValue_setCurrentThresholds(Genome genome) { this.currentOversoldThreshold = Convert.ToDouble(genome.Genes()[0])/ Convert.ToDouble(this.divisorForThresholdComputation); this.currentOverboughtThreshold = Convert.ToDouble(genome.Genes()[1])/ Convert.ToDouble(this.divisorForThresholdComputation); } private int getFitnessValue_getDaysOnTheMarket(double[] equityLine) { int returnValue = 0; foreach(double equityReturn in equityLine) if(equityReturn > 0.0) returnValue++; return returnValue; } //fitness is a sharpe-ratio based indicator for the equity line resulting //from applying the strategy public override double GetFitnessValue(Genome genome) { double returnValue = -1.0; this.portfolioRatesOfReturn = this.getPortfolioRatesOfReturn(genome.Genes()); this.portfolioValues = this.getPortfolioMovingValues(); this.getFitnessValue_setCurrentThresholds(genome); double[] equityLine = this.getFitnessValue_getEquityLineRates(); double fitness = Double.NaN; if(this.getFitnessValue_getDaysOnTheMarket(equityLine) > equityLine.Length / 2) //if the genome represents a portfolio that stays on the market //at least half of the theoretical days fitness = AdvancedFunctions.GetSharpeRatio(equityLine); if(!double.IsNaN(fitness) && !double.IsInfinity(fitness)) returnValue = fitness; return returnValue; } private double[] getFitnessValue_getEquityLineRates() { double[] returnValue = new double[this.PortfolioRatesOfReturn.Length]; double coefficient = 0.0; for(int i = 0; i<this.PortfolioRatesOfReturn.Length - 1;i++) { if(this.portfolioValues[i] >= 1.0 + this.currentOverboughtThreshold) //portfolio is overbought coefficient = -1.0; else if(this.portfolioValues[i] <= 1.0 - this.currentOversoldThreshold && this.portfolioValues[i] > 0.0) //portfolio is oversold coefficient = 1.0; returnValue[i + 1] = coefficient * this.PortfolioRatesOfReturn[i + 1]; } return returnValue; } protected override double getTickerWeight(int[] genes, int tickerPositionInGenes) { return 1.0/(genes.Length - 2); //two genes are for thresholds } protected override double[] getPortfolioRatesOfReturn(int[] genes) { double[] returnValue = new double[this.numberOfExaminedReturns]; for(int i = 0; i<returnValue.Length; i++) { for(int j=2; j<genes.Length; j++)//the first two genes are for thresholds returnValue[i] += this.getPortfolioRatesOfReturn_getRateOfTickerToBeAddedToTheArray(genes,j,i); } return returnValue; } public override object Decode(Genome genome) { string[] arrayOfTickers = new string[genome.Genes().Length - 2]; int geneForTicker; for(int genePosition = 2; genePosition < genome.Genes().Length; genePosition++) { geneForTicker = (int)genome.Genes().GetValue(genePosition); arrayOfTickers[genePosition - 2] = this.decode_getTickerCodeForLongOrShortTrade(geneForTicker); } GenomeMeaningPVO meaning = new GenomeMeaningPVO( arrayOfTickers, Convert.ToDouble(genome.Genes()[0])/Convert.ToDouble(this.divisorForThresholdComputation), Convert.ToDouble(genome.Genes()[1])/Convert.ToDouble(this.divisorForThresholdComputation), this.numDaysForOscillatingPeriod); return meaning; } public override Genome[] GetChilds(Genome parent1, Genome parent2) { //in this simple implementation //child have the tickers of one parent //and the thresholds of the other Genome[] childs = new Genome[2]; childs[0] = parent1.Clone(); childs[1] = parent2.Clone(); //exchange of genes coding thresholds childs[0].SetGeneValue(parent2.GetGeneValue(0),0); childs[0].SetGeneValue(parent2.GetGeneValue(1),1); childs[1].SetGeneValue(parent1.GetGeneValue(0),0); childs[1].SetGeneValue(parent1.GetGeneValue(1),1); return childs; } public override int GetNewGeneValue(Genome genome, int genePosition) { // in this implementation only new gene values pointing to tickers // must be different from the others already stored int minValueForGene = genome.GetMinValueForGenes(genePosition); int maxValueForGene = genome.GetMaxValueForGenes(genePosition); int returnValue = minValueForGene; if( minValueForGene != maxValueForGene) { returnValue = GenomeManagement.RandomGenerator.Next(minValueForGene, maxValueForGene + 1); while(genePosition > 1 && GenomeManipulator.IsTickerContainedInGenome(returnValue,genome,2,genome.Size - 1)) //while in the given position has to be stored //a new gene pointing to a ticker and //the proposed returnValue points to a ticker //already stored in the given genome { // a new returnValue has to be generated returnValue = GenomeManagement.RandomGenerator.Next(minValueForGene, maxValueForGene + 1); } } return returnValue; } public override void Mutate(Genome genome, double mutationRate) { // in this implementation only one gene is mutated int genePositionToBeMutated = GenomeManagement.RandomGenerator.Next(genome.Size); int minValueForGene = genome.GetMinValueForGenes(genePositionToBeMutated); int maxValueForGene = genome.GetMaxValueForGenes(genePositionToBeMutated); if(minValueForGenes != maxValueForGenes) { int newValueForGene = GenomeManagement.RandomGenerator.Next(minValueForGene, maxValueForGene +1); while(genePositionToBeMutated > 1 && GenomeManipulator.IsTickerContainedInGenome(newValueForGene,genome,2,genome.Size - 1)) //while in the proposed genePositionToBeMutated has to be stored //a new gene pointing to a ticker and //the proposed newValueForGene points to a ticker //already stored in the given genome { newValueForGene = GenomeManagement.RandomGenerator.Next(minValueForGene, maxValueForGene +1); } GenomeManagement.MutateOneGene(genome, mutationRate, genePositionToBeMutated, newValueForGene); } } } } --- NEW FILE: GenomeMeaningPVO.cs --- /* QuantProject - Quantitative Finance Library GenomeMeaningPVO.cs Copyright (C) 2003 Marco Milletti This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ using System; using QuantProject.Scripts.TickerSelectionTesting.EfficientPortfolios; namespace QuantProject.Scripts.TechnicalAnalysisTesting.Oscillators.FixedLevelOscillators.PortfolioValueOscillator { /// <summary> /// This is the class representing the meaning for genome /// for the Portfolio Value Oscillator strategy /// </summary> [Serializable] public class GenomeMeaningPVO : GenomeMeaning { private double oversoldThreshold; private double overboughtThreshold; private int numDaysForOscillatingPeriod; public double OversoldThreshold { get{return this.oversoldThreshold;} } public double OverboughtThreshold { get{return this.overboughtThreshold;} } public int NumDaysForOscillatingPeriod { get{return this.numDaysForOscillatingPeriod;} } public GenomeMeaningPVO(string[] tickers, double[] tickersPortfolioWeights, double oversoldThreshold, double overboughtThreshold, int numDaysForOscillatingPeriod): base(tickers, tickersPortfolioWeights) { this.oversoldThreshold = oversoldThreshold; this.overboughtThreshold = overboughtThreshold; this.numDaysForOscillatingPeriod = numDaysForOscillatingPeriod; } public GenomeMeaningPVO(string[] tickers, double oversoldThreshold, double overboughtThreshold, int numDaysForOscillatingPeriod): base(tickers) { this.oversoldThreshold = oversoldThreshold; this.overboughtThreshold = overboughtThreshold; this.numDaysForOscillatingPeriod = numDaysForOscillatingPeriod; } } } --- NEW FILE: RunPVO.cs --- /* QuantProject - Quantitative Finance Library RunPVO.cs Copyright (C) 2003 Marco Milletti This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ using System; using System.Collections; using System.Data; using QuantProject.ADT; using QuantProject.ADT.Optimizing.Genetic; using QuantProject.Business.DataProviders; using QuantProject.Business.Financial.Accounting; using QuantProject.Business.Financial.Accounting.Reporting; using QuantProject.Business.Financial.Instruments; using QuantProject.Business.Financial.Ordering; using QuantProject.Business.Scripting; using QuantProject.Business.Strategies; using QuantProject.Business.Testing; using QuantProject.Business.Timing; using QuantProject.Data.DataProviders; using QuantProject.Data.Selectors; using QuantProject.Scripts.TickerSelectionTesting.EfficientPortfolios; using QuantProject.Presentation.Reporting.WindowsForm; using QuantProject.ADT.FileManaging; using QuantProject.Scripts.WalkForwardTesting.LinearCombination; namespace QuantProject.Scripts.TechnicalAnalysisTesting.Oscillators.FixedLevelOscillators.PortfolioValueOscillator { /// <summary> /// Script that implements an oscillating strategy, /// based on the classical technical indicator /// RelativeStrengthIndex - RSI /// </summary> [Serializable] public class RunPVO : RunEfficientPortfolio { private int minLevelForOversoldThreshold; private int maxLevelForOversoldThreshold; private int minLevelForOverboughtThreshold; private int maxLevelForOverboughtThreshold; private int divisorForThresholdComputation; //to be used by the optimizer private int numDaysBetweenEachOptimization; private double maxAcceptableCloseToCloseDrawdown; private int numDaysForOscillatingPeriod; public RunPVO(string tickerGroupID, int maxNumOfEligibleTickersForOptimization, int numberOfTickersToBeChosen, int numDaysForOptimizationPeriod, int generationNumberForGeneticOptimizer, int populationSizeForGeneticOptimizer, string benchmark, DateTime startDate, DateTime endDate, int numDaysForOscillatingPeriod, int minLevelForOversoldThreshold, int maxLevelForOversoldThreshold, int minLevelForOverboughtThreshold, int maxLevelForOverboughtThreshold, int divisorForThresholdComputation, int numDaysBetweenEachOptimization, PortfolioType portfolioType, double maxAcceptableCloseToCloseDrawdown, double maxRunningHours): base(tickerGroupID, maxNumOfEligibleTickersForOptimization, numberOfTickersToBeChosen, numDaysForOptimizationPeriod, generationNumberForGeneticOptimizer, populationSizeForGeneticOptimizer, benchmark, startDate, endDate, 0.0, portfolioType, maxRunningHours) { this.ScriptName = "PVO_SR_NoWeights_PriceSel"; this.minLevelForOversoldThreshold = minLevelForOversoldThreshold; this.maxLevelForOversoldThreshold = maxLevelForOversoldThreshold; this.minLevelForOverboughtThreshold = minLevelForOverboughtThreshold; this.maxLevelForOverboughtThreshold = maxLevelForOverboughtThreshold; this.divisorForThresholdComputation = divisorForThresholdComputation; this.maxAcceptableCloseToCloseDrawdown = maxAcceptableCloseToCloseDrawdown; this.numDaysForOscillatingPeriod = numDaysForOscillatingPeriod; this.numDaysBetweenEachOptimization = numDaysBetweenEachOptimization; } #region auxiliary overriden methods for Run protected override void run_initializeEndOfDayTimerHandler() { this.endOfDayTimerHandler = new EndOfDayTimerHandlerPVO(this.tickerGroupID, this.numberOfEligibleTickers, this.numberOfTickersToBeChosen, this.numDaysForOptimizationPeriod, this.account, this.generationNumberForGeneticOptimizer, this.populationSizeForGeneticOptimizer, this.benchmark, this.numDaysForOscillatingPeriod, this.minLevelForOversoldThreshold, this.maxLevelForOversoldThreshold, this.minLevelForOverboughtThreshold, this.maxLevelForOverboughtThreshold, this.divisorForThresholdComputation, this.numDaysBetweenEachOptimization, this.portfolioType, this.maxAcceptableCloseToCloseDrawdown); } protected override void run_initializeHistoricalQuoteProvider() { this.historicalQuoteProvider = new HistoricalAdjustedQuoteProvider(); } protected override void run_addEventHandlers() { this.endOfDayTimer.MarketClose += new MarketCloseEventHandler( this.endOfDayTimerHandler.MarketCloseEventHandler); this.endOfDayTimer.MarketClose += new MarketCloseEventHandler( this.checkDateForReport); this.endOfDayTimer.OneHourAfterMarketClose += new OneHourAfterMarketCloseEventHandler( this.endOfDayTimerHandler.OneHourAfterMarketCloseEventHandler); } public override void SaveScriptResults() { string fileName = this.scriptName + "OsDays_" + numDaysForOscillatingPeriod + "_From_" + this.tickerGroupID + "_" + this.numberOfEligibleTickers + "_DaysForOpt" + this.numDaysForOptimizationPeriod + "Tick" + this.numberOfTickersToBeChosen + "GenN°" + this.generationNumberForGeneticOptimizer + "PopSize" + this.populationSizeForGeneticOptimizer + Convert.ToString(this.portfolioType); string dirNameWhereToSaveReports = System.Configuration.ConfigurationSettings.AppSettings["ReportsArchive"] + "\\" + this.ScriptName + "\\"; string dirNameWhereToSaveTransactions = System.Configuration.ConfigurationSettings.AppSettings["TransactionsArchive"] + "\\" + this.ScriptName + "\\"; string dirNameWhereToSaveBestGenomes = System.Configuration.ConfigurationSettings.AppSettings["GenomesArchive"] + "\\" + this.ScriptName + "\\"; this.checkDateForReport_createDirIfNotPresent(dirNameWhereToSaveBestGenomes); OptimizationOutput optimizationOutput = new OptimizationOutput(); foreach(GenomeRepresentation genomeRepresentation in this.endOfDayTimerHandler.BestGenomes) optimizationOutput.Add(genomeRepresentation); ObjectArchiver.Archive(optimizationOutput, dirNameWhereToSaveBestGenomes + fileName + ".bgn"); //default report with numIntervalDays = 1 AccountReport accountReport = this.account.CreateReport(fileName,1, this.endOfDayTimer.GetCurrentTime(), this.benchmark, new HistoricalAdjustedQuoteProvider()); this.checkDateForReport_createDirIfNotPresent(dirNameWhereToSaveReports); ObjectArchiver.Archive(accountReport, dirNameWhereToSaveReports + fileName + ".qPr"); this.endOfDayTimer.Stop(); } #endregion } } --- NEW FILE: EndOfDayTimerHandlerPVO.cs --- /* QuantProject - Quantitative Finance Library EndOfDayTimerHandlerPVO.cs Copyright (C) 2003 Marco Milletti This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ using System; using System.Data; using System.Collections; using QuantProject.ADT; using QuantProject.Business.Financial.Accounting; using QuantProject.Business.Financial.Instruments; using QuantProject.Business.Financial.Ordering; using QuantProject.Business.Timing; using QuantProject.Business.Strategies; using QuantProject.Data; using QuantProject.Data.DataProviders; using QuantProject.Data.Selectors; using QuantProject.Data.DataTables; using QuantProject.ADT.Optimizing.Genetic; using QuantProject.Scripts.TickerSelectionTesting.EfficientPortfolios; using QuantProject.Scripts.WalkForwardTesting.LinearCombination; namespace QuantProject.Scripts.TechnicalAnalysisTesting.Oscillators.FixedLevelOscillators.PortfolioValueOscillator { /// <summary> /// Implements MarketOpenEventHandler and MarketCloseEventHandler /// These handlers contain the core strategy for the Portfolio Value /// Oscillator /// </summary> [Serializable] public class EndOfDayTimerHandlerPVO : EndOfDayTimerHandler { private int minLevelForOversoldThreshold; private int maxLevelForOversoldThreshold; private int minLevelForOverboughtThreshold; private int maxLevelForOverboughtThreshold; private int divisorForThresholdComputation; protected int numDaysForOscillatingPeriod; protected double currentOversoldThreshold; protected double currentOverboughtThreshold; private double maxAcceptableCloseToCloseDrawdown; private bool stopLossConditionReached; private double currentAccountValue; private double previousAccountValue; private int numDaysBetweenEachOptimization; private int numDaysElapsedSinceLastOptimization; private DateTime lastCloseDate; private IGenomeManager iGenomeManager; private int seedForRandomGenerator; private bool portfolioHasBeenOverbought; private bool portfolioHasBeenOversold; public EndOfDayTimerHandlerPVO(string tickerGroupID, int numberOfEligibleTickers, int numberOfTickersToBeChosen, int numDaysForOptimizationPeriod, Account account, int generationNumberForGeneticOptimizer, int populationSizeForGeneticOptimizer, string benchmark, int numDaysForOscillatingPeriod, int minLevelForOversoldThreshold, int maxLevelForOversoldThreshold, int minLevelForOverboughtThreshold, int maxLevelForOverboughtThreshold, int divisorForThresholdComputation, int numDaysBetweenEachOptimization, PortfolioType portfolioType, double maxAcceptableCloseToCloseDrawdown): base(tickerGroupID, numberOfEligibleTickers, numberOfTickersToBeChosen, numDaysForOptimizationPeriod, account, generationNumberForGeneticOptimizer, populationSizeForGeneticOptimizer, benchmark, 0.0, portfolioType) { this.numDaysForOscillatingPeriod = numDaysForOscillatingPeriod; this.minLevelForOversoldThreshold = minLevelForOversoldThreshold; this.maxLevelForOversoldThreshold = maxLevelForOversoldThreshold; this.minLevelForOverboughtThreshold = minLevelForOverboughtThreshold; this.maxLevelForOverboughtThreshold = maxLevelForOverboughtThreshold; this.divisorForThresholdComputation = divisorForThresholdComputation; this.maxAcceptableCloseToCloseDrawdown = maxAcceptableCloseToCloseDrawdown; this.stopLossConditionReached = false; this.currentAccountValue = 0.0; this.previousAccountValue = 0.0; this.numDaysBetweenEachOptimization = numDaysBetweenEachOptimization; this.seedForRandomGenerator = ConstantsProvider.SeedForRandomGenerator; this.portfolioHasBeenOverbought = false; this.portfolioHasBeenOversold = false; } #region MarketCloseEventHandler protected void marketCloseEventHandler_updateStopLossCondition() { this.previousAccountValue = this.currentAccountValue; this.currentAccountValue = this.account.GetMarketValue(); if((this.currentAccountValue - this.previousAccountValue) /this.previousAccountValue < -this.maxAcceptableCloseToCloseDrawdown) { this.stopLossConditionReached = true; } else { this.stopLossConditionReached = false; } } protected virtual double getCurrentChosenTickersValue(IndexBasedEndOfDayTimer timer) { double returnValue = 999.0; try { DateTime initialDate = (DateTime)timer.IndexQuotes.Rows[timer.CurrentDateArrayPosition - this.numDaysForOscillatingPeriod + 2]["quDate"]; //so to replicate exactly in sample scheme, where only numOscillatingDay - 1 returns //are computed DateTime finalDate = (DateTime)timer.IndexQuotes.Rows[timer.CurrentDateArrayPosition]["quDate"]; returnValue = SignedTicker.GetCloseToClosePortfolioReturn( this.chosenTickers, this.chosenTickersPortfolioWeights, initialDate,finalDate) + 1.0; } catch(MissingQuotesException ex) { ex = ex; } return returnValue; } private void marketCloseEventHandler_reverseIfNeeded(IndexBasedEndOfDayTimer timer) { double currentChosenTickersValue = this.getCurrentChosenTickersValue(timer); if(currentChosenTickersValue != 999.0) //currentChosenTickersValue has been properly computed { if(this.portfolioType == PortfolioType.ShortAndLong) //it is possible to reverse positions { if(currentChosenTickersValue >= 1.0 + currentOverboughtThreshold && this.portfolioHasBeenOversold) //open positions derive from an overSold period but now //an the overbought threshold has been reached { this.reversePositions(); this.portfolioHasBeenOversold = false; this.portfolioHasBeenOverbought = true; } if(currentChosenTickersValue <= 1.0 - currentOversoldThreshold && this.portfolioHasBeenOverbought) //open positions derive from an overSold period but now //an the overbought threshold has been reached { this.reversePositions(); this.portfolioHasBeenOversold = true; this.portfolioHasBeenOverbought = false; } } } } private void marketCloseEventHandler_openPositions(IndexBasedEndOfDayTimer timer) { double currentChosenTickersValue = this.getCurrentChosenTickersValue(timer); if(currentChosenTickersValue != 999.0) //currentChosenTickersValue has been properly computed { if(currentChosenTickersValue >= 1.0 + currentOverboughtThreshold && this.portfolioType == PortfolioType.ShortAndLong) { SignedTicker.ChangeSignOfEachTicker(this.chosenTickers); //short the portfolio try { base.openPositions(this.chosenTickers); this.portfolioHasBeenOverbought = true; this.portfolioHasBeenOversold = false; } catch(Exception ex) { ex = ex; } finally { SignedTicker.ChangeSignOfEachTicker(this.chosenTickers); } } else if (currentChosenTickersValue <= 1.0 - currentOversoldThreshold) { try { base.openPositions(this.chosenTickers); this.portfolioHasBeenOverbought = false; this.portfolioHasBeenOversold = true; } catch(Exception ex) { ex = ex; } } } } protected virtual void marketCloseEventHandler_closePositionsIfNeeded() { if(this.stopLossConditionReached || this.numDaysElapsedSinceLastOptimization + 1 == this.numDaysBetweenEachOptimization ) { base.closePositions(); //a new optimization is needed, now this.chosenTickers[0] = null; //when positions are closed, these parameters //have to be reset to false this.portfolioHasBeenOverbought = false; this.portfolioHasBeenOversold = false; } } public override void MarketCloseEventHandler( Object sender , EndOfDayTimingEventArgs endOfDayTimingEventArgs ) { //this.marketCloseEventHandler_updateStopLossCondition(); this.marketCloseEventHandler_closePositionsIfNeeded(); if(this.chosenTickers[0] != null) //tickers to buy have been chosen by the optimizer { if(this.account.Portfolio.Count == 0) this.marketCloseEventHandler_openPositions((IndexBasedEndOfDayTimer)sender); //positions are opened only if thresholds are reached else//there are some opened positions this.marketCloseEventHandler_reverseIfNeeded((IndexBasedEndOfDayTimer)sender);; } } #endregion #region OneHourAfterMarketCloseEventHandler protected DataTable getSetOfTickersToBeOptimized(DateTime currentDate) { SelectorByGroup temporizedGroup = new SelectorByGroup(this.tickerGroupID, currentDate); DataTable tickersFromGroup = temporizedGroup.GetTableOfSelectedTickers(); int numOfTickersInGroupAtCurrentDate = tickersFromGroup.Rows.Count; SelectorByAverageRawOpenPrice byPrice = new SelectorByAverageRawOpenPrice(tickersFromGroup,false,currentDate, currentDate.AddDays(-30), numOfTickersInGroupAtCurrentDate, 25,500, 0.0001,100); SelectorByLiquidity mostLiquidSelector = new SelectorByLiquidity(byPrice.GetTableOfSelectedTickers(), false,currentDate.AddDays(-this.numDaysForOptimizationPeriod), currentDate, this.numberOfEligibleTickers); SelectorByQuotationAtEachMarketDay quotedAtEachMarketDayFromMostLiquid = new SelectorByQuotationAtEachMarketDay(mostLiquidSelector.GetTableOfSelectedTickers(), false, currentDate.AddDays(-this.numDaysForOptimizationPeriod), currentDate, this.numberOfEligibleTickers, this.benchmark); return quotedAtEachMarketDayFromMostLiquid.GetTableOfSelectedTickers(); } private void addPVOGenomeToBestGenomes(Genome genome, DateTime firstOptimizationDate, DateTime secondOptimizationDate, int eligibleTickers, int daysForOscillatingPeriod, PortfolioType portfolioType, int createdGenerations, double oversoldThreshold, double overboughtThreshold) { if(this.bestGenomes == null) this.bestGenomes = new ArrayList(); this.bestGenomes.Add(new GenomeRepresentation(genome, firstOptimizationDate, secondOptimizationDate, genome.Generation, eligibleTickers, daysForOscillatingPeriod, portfolioType, createdGenerations, oversoldThreshold, overboughtThreshold)); } protected virtual void setTickers(DateTime currentDate, bool setGenomeCounter) { DataTable setOfTickersToBeOptimized = this.getSetOfTickersToBeOptimized(currentDate); if(setOfTickersToBeOptimized.Rows.Count > this.chosenTickers.Length*2) //the optimization process is meaningful only if the initial set of tickers is //larger than the number of tickers to be chosen { this.iGenomeManager = new GenomeManagerPVO(setOfTickersToBeOptimized, currentDate.AddDays(-this.numDaysForOptimizationPeriod), currentDate, this.numberOfTickersToBeChosen, this.numDaysForOscillatingPeriod, this.minLevelForOversoldThreshold, this.maxLevelForOversoldThreshold, this.minLevelForOverboughtThreshold, this.maxLevelForOverboughtThreshold, this.divisorForThresholdComputation, this.portfolioType); GeneticOptimizer GO = new GeneticOptimizer(this.iGenomeManager, this.populationSizeForGeneticOptimizer, this.generationNumberForGeneticOptimizer, this.seedForRandomGenerator); if(setGenomeCounter) this.genomeCounter = new GenomeCounter(GO); GO.MutationRate = 0.4; GO.Run(false); this.chosenTickers = ((GenomeMeaningPVO)GO.BestGenome.Meaning).Tickers; this.chosenTickersPortfolioWeights = ((GenomeMeaningPVO)GO.BestGenome.Meaning).TickersPortfolioWeights; this.currentOversoldThreshold = ((GenomeMeaningPVO)GO.BestGenome.Meaning).OversoldThreshold; this.currentOverboughtThreshold = ((GenomeMeaningPVO)GO.BestGenome.Meaning).OverboughtThreshold; this.addPVOGenomeToBestGenomes(GO.BestGenome,((GenomeManagerForEfficientPortfolio)this.iGenomeManager).FirstQuoteDate, ((GenomeManagerForEfficientPortfolio)this.iGenomeManager).LastQuoteDate, setOfTickersToBeOptimized.Rows.Count, this.numDaysForOscillatingPeriod, this.portfolioType, GO.GenerationCounter, this.currentOversoldThreshold, this.currentOverboughtThreshold); } //else it will be buyed again the previous optimized portfolio //that's it the actual chosenTickers member } /// <summary> /// Handles a "One hour after market close" event. /// </summary> /// <param name="sender"></param> /// <param name="eventArgs"></param> public override void OneHourAfterMarketCloseEventHandler( Object sender , EndOfDayTimingEventArgs endOfDayTimingEventArgs ) { this.lastCloseDate = endOfDayTimingEventArgs.EndOfDayDateTime.DateTime; this.seedForRandomGenerator++; this.numDaysElapsedSinceLastOptimization++; this.orders.Clear(); if((this.numDaysElapsedSinceLastOptimization == this.numDaysBetweenEachOptimization)) //num days without optimization has elapsed { this.setTickers(endOfDayTimingEventArgs.EndOfDayDateTime.DateTime, false); //sets tickers to be chosen next Market Close event this.numDaysElapsedSinceLastOptimization = 0; } } #endregion } } |