copio e incollo senza commenti questo codice di Bob Fulks su come aggiustare e riscrivere il codice di Oddball per renderlo più robusto Fulks è una delle persone più serie che ci siano in giro nell'ambiente dei trading systems e quello che scrive qua sotto vale parecchi $$$$ E' una fortuna che gente come Bob Fulks trovi il tempo di scrivere queste cose su Omegalist ---------------------------------------------------------- My "more robust" code still has one source of error that I had suspected was not important but turns out to be important. It is also a problem in the original OddBall code. So how could a such a simple system with basically two lines of code include an error? Read on. (The following explanation assumes 7 natural hour bars corresponding to the 0930 to 1600 market hours. If you use the futures market hours you might have 8 natural hour bars but the source of the error is the same.) The system is intended to compare the number of NYSE advancing issues today with the number of advancing issues yesterday at the same time of day. With 7 natural hour bars in a day, that would require: RateOfChange(Close of data2, 7); which is what is in the original code. We would thus expect the time stamp on the current bar to be the same as the time stamp on the bar 7 bars ago. That is mostly true but not always. The worst source of error is short trading days that contain fewer than 7 natural hour bars such as the day after Thanksgiving. To test for this I tried some experiments. I just ran a quick test on my data and found that in 1000 days of data there were 91 bars where the time stamps on the two bars being compared were not the same. So I wondered if this was important. Walk through one such case: On 11/23/01 there are 5 natural hour bars. So at the 1000 bar on 11/26/01, the original code would compare that 1000 bar with the 1500 bar on 11/21/01 - clearly not what was intended. I then tried two different new versions to test this. The code for my experiment is appended at the end of this post in case you would like to duplicate the experiment. ---- Version 1 = Original code (xMode = 1) This was the original code. We know it includes comparisons on 91 bars with inconsistent time stamps for this data. ---- Version 2 (xMode = 2) This version of the system restricted the RateOfChange calculation to only those bars where the time stamps on the two bars were the same, basically rejecting the 91 bars with the inconsistent time stamps. (It held the RateOfChange value over bars where the time stamps were different.) There were fewer trades and the results were poorer than with the the original code. ---- Version 3 (xMode = 3) This version does not assume anything about the number of bars back to the corresponding time bar of yesterday. It saves the bar number of each bar in an array based upon it's time stamp so that it can find the corresponding past time bar if one exists. This allows the code to use every bar available. This version found only 26 bars with no corresponding time stamps the previous day and produced better results than Version 2. ---- Results: This is for trading 250 shares of $SPX (S&P500 Index) with no costs for 1000 days of data ending 3/8/02: Original Version 2 Version 3 Net Profit $511,000 $452,000 $503,000 # Trades 985 969 983 % Profitable 48% 47% 48% Drawdown $56,000 $59,000 56,000 Profit Factor 1.44 1.38 1.43 ROA 900% 768% 895% Sharpe Ratio 1.95 1.71 1.95 Original - So the spurious bars with the incorrect time stamp in the original version were actually improving the results but is an unpredictable way. It include 91 incorrect comparisons. Version 2 - Leaving out all 91 mismatched time stamps reduced trades and performance. It basically held previous positions for most days following a short trading day. Version 3 - Using all available time stamps accurately improved profits to near the original and executes the strategy as accurately as possible. There were only 26 bars for which no corresponding time bar was available in the 1000 days of data. I found this interesting - another example of how even simple code can contain hidden errors that cause it to behave differently than intended... Bob Fulks { ******************************************************************* System : bf.OddBall.2 Last Edit : 3/17/02 Provided By : Bob Fulks Description : This is three different versions of Mark Brown's OddBall system. It is intended to test the effects of comparing bars with different time stamps. Data1 is the market being traded. Data2 is the number of advancing issues on the NYSE. Extra input: xMode = 1 Original version for comparison xMode = 2 Eliminates comparisons where the time stamps on the two bars being compared are different. xMode = 3 Uses an array to save the bar number of the corresponding time bars of yesterday, without assuming how many bars back it is, so that it can use every available bar. Use 60 minute natural hour bars day session only. ********************************************************************} Input: RL(7), BZ(3), SZ(1), xMode(1); Vars: ADV(Close of data2), ROC(0), ErrCnt(0), DCount(0), j(0), k(0), LDate(0); Array: aBar[10](0); if Date <> Date[1] then begin {New day initialization} DCount = DCount + 1; {Count days to allow 2 days of initialization} LDate = Date[1]; {Save previous date} end; ADV = Close of data2; {Data series for advances} if Time > 0930 and Time <= 1600 then begin if xMode = 1 then ROC = RateOfChange(ADV, RL); if xMode = 2 then begin {Calculate for matching bars only} if Time[RL] = Time then ROC = RateOfChange(ADV, RL) else begin ErrCnt = ErrCnt + 1; {Count and print errors} Print(ErrCnt:5:0, DCount:5:0, Date:8:0, LDate:8:0, Date[RL]:8:0, Time:5:0, Time[RL]:5:0); end; end; if xMode = 3 then begin j = (TimeToMinutes(Time) - 600) / 60; {Calculate location in array} k = MinList(CurrentBar - aBar[j], 50); {Get bars back to same bar yesterday} if (Date[k] = LDate and Time[k] = Time) or DCount <= 2 then begin ROC = RateOfChange(ADV, k); {Calculate rate of change} end else begin ErrCnt = ErrCnt + 1; {Count and print errors} Print(ErrCnt:5:0, DCount:5:0, Date:8:0, LDate:8:0, Date[k]:8:0, Time:5:0, Time[k]:5:0, j:4:0, k:4:0); end; aBar[j] = CurrentBar; {Save bar number in array} end; {--------------------System Code--------------------} if DCount >= 3 then begin if ROC > BZ then Buy on Close; if ROC < SZ then Sell on Close; end; end; {------------------Indicator Code--------------------} { Plot1(ROC, "1"); {Plot as a line} if ErrCnt <> ErrCnt[1] then Plot3(ROC, "3"); {Plot as a fat Point} Plot4(0, "4"); {Plot as a line} end; } {--------------------End Code--------------------} Edited by - gzibordi on 3/17/2002 22:1:35