Tools, Techniques, and Training for Nirvana Platforms 
OmniTrader, VisualTrader, OmniFunds & OmniVest 
 
 


Psalm 37:5 (NKJV) ... Commit your way to the Lord, trust also in Him, and He will bring it to pass. 
OScript for CAR, MDD, and Calmar Ratio  

JimDean 
 
Owner/Admin Posts: 3886 Location: USA: GA, Lawrenceville  The Calmar ratio is considered by many to be a good core measure for the tradeability of a strategy. It is: Calmar = CAR / MDD where CAR = compound annual rate of return (as pct), and MDD = maximum drawdown since a prior high (as pct) ... both of which are based on the Equity Curve (avail now via OVest Ver2) ===== We can write an OScript formula for CAR: %CAR = 100* ((Final/Initial)^(1/Years)1 ) where: Final = final close (end of todate window) Initial = initial close (start of window) Years = # trading days / 252 days/year ... (somewhere btwn 250 & 260 trading days/year) This would be expressed in OScript as: 100*( ( C/C[bar] ) ^ ( 1/ (bar/252) ) 1 ) ... note that "bar" is the barnumber of the tradingday, starting since the beginning ... I don't know if it is reset based on the Starting Date Range or not ... so, it might go back all the way to the earliest possible Equity start date (1/1/2000?) ==== ... on to the next post for MDD, and two more after that to get to Calmar ... put on your seatbelts! Thread moved by JimDean on 8/4/2014 8:49 AM from Markets & Methods > OmniVest, Money Mgmt & Risk Control > OScript for CAR, MDD, and Calmar Ratio  
JimDean 
 
Owner/Admin Posts: 3886 Location: USA: GA, Lawrenceville  The easy part is done. %MDD is a lot messier to deal with. As I understand it, Nirvana calculates MDD as: 100* (HighestSoFar  LowestSinceThatHi) / HighestSoFar) In OScript, HighestSoFar = HHV(C,bar). That's the easy part. But in order to know the lowest SINCE that high, we have to find out *what bar* the High occured on, then check the LLV(C,BarsSinceHigh). It's easy to do that in OLang, but in OScript it's impossible to do cleanly, because OScript does not have a "BarsSinceEvent" function like other script languages often do (it's been requested a lot in the past tho :~). ===== HOWEVER ... if we break it down into pieces, we can solve it (for most situations) in OScript. That is, we can calc the drawdown for a SINGLE DAY (ie how much did price drop since yesterday) as: (C[1]  C)/ C[1] ... or, the drawdown since the highest of the prior two days as: (HHV(C,2)[1]  C) / HHV(C,2)[1] ... or, the drawdown since the highest of the prior two days as: (HHV(C,3)[1]  C) / HHV(C,3)[1] ... or, the drawdown since the highest of the prior two days as: (HHV(C,4)[1]  C) / HHV(C,4)[1] ... or, the drawdown since the highest of the prior five days as: (HHV(C,5)[1]  C) / HHV(C,5)[1] ... and so on Using that approach, an OScript formula can be built, with a finite number of testwindows ... that is, you need to decide ahead of time what the maximum timegap might occur between your highesthigh and a subsequent lowestlow. Actually, this is sort of an "extendedpainperiod" kind of number ... if you hit an equity high with a strat, and then it just starts to degrade continually with a few minor high retracements, then sooner or later you will want to get out even if the overall percentage drawdown isn't too huge ... that is, how long will you put up with NOT recovering your equity, before you trash the strategy and move on? So, that extendedpainperiod defines how many little "chunks" of drawdownchecks you'll need in the formula. Let's say that your threshold is five days (not very much I know but it saves typing :~) The five checks are listed above. You can put them together as: HHV((C[1]  C)/ C[1],bar) > MaxAllowed orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > MaxAllowed orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > MaxAllowed orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > MaxAllowed orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > MaxAllowed ... and you could extend this out for as many windows as you want ... but be cautioned ... HHV (and Sum and LLV) functions take up significant CPU time. The formula returns "true" (ie a numeric value of 1) if ANY of the six tests finds a drawdown that is too big. The "orelse" terms act like "or", with an important addition ... in theory, the first clause is found to be true, then the orelse is "satisfied", and it does not bother calculating the other clauses. This saves some CPU time, but only for any bar that we actually FIND the drawdown limit is exceeded. But, every little bit helps. OK ... the formula above checks the drawdown for ONE PARTICULAR day ... but we want to find out the worst drawdown that occurred for ANY PRIOR day as well, since the beginning. To do this, we use the Sum() function that I've discussed elsewhere as a nifty means of checking MANY conditions in one SHORT formula. So, to process the foregoing test for all the prior bars, the formula becomes: Sum( ( HHV((C[1]  C)/ C[1],bar) > MaxAllowed orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > MaxAllowed orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > MaxAllowed orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > MaxAllowed orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > MaxAllowed ), bar) < 0 That formula will take a long time to calc. And please note my caution in the prior post, regarding how far back the "bar" range goes (may or may not be tied to the input date range). The Sum function add's up the individual ruleset results, each of which has been converted from True/False to 1/0 via the parentheses around the full rule. If the sum of those is nonzero, then somewhere along the way, the MaxAllowed drawdown was exceeded. OK ... that's the heart of it ... next post puts it in perspective ... Thread moved by JimDean on 8/4/2014 8:49 AM from Markets & Methods > OmniVest, Money Mgmt & Risk Control > OScript for CAR, MDD, and Calmar Ratio  
JimDean 
 
Owner/Admin Posts: 3886 Location: USA: GA, Lawrenceville  So ... in the prior two posts I derived OScripts for CAR and MDD, which are the two components of Calmar. Actually, the script for MDD does not TELL you the MDD, but rather, whether a given MDD threshold was reached. Unfortunately this is one of the consequences of not having a BarsSince function in OScript. So, how do we know what the MDD is? Answer: we can APPROXIMATE it, by "binning" the MDD calc's. Let's say our max allowed MDD is 20%. The prior formula will tell us "yes or no" whether that value was ever hit: Sum( ( HHV((C[1]  C)/ C[1],bar) > .2 orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > .2 orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > .2 orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > .2 orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > .2 ), bar) < 0 Now, if we enclose THAT formula in paren's, it will return a 1 or 0  which can be converted to a 20% output: 20 * ( Sum( ( HHV((C[1]  C)/ C[1],bar) > .2 orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > .2 orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > .2 orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > .2 orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > .2 ), bar) < 0 ) Now, we generate another formula that checks for 15%: 15 * ( Sum( ( HHV((C[1]  C)/ C[1],bar) > .15 orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > .15 orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > .15 orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > .15 orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > .15 ), bar) < 0 ) Similarly, generate ones for 10% and 5%. Remember ... each of these formulae return a value of ZERO if its particular threshold is NOT hit. So, we can ADD the results ... the answer will be 0, 5, 10, 15, or 20. BUT, we do not want the Calmar formula to divide by MDD=0, so let's make the lowest value = 1 instead, by adjusting the very first term of each component. Here we goooo ... MDD = 1 19 * ( Sum( ( HHV((C[1]  C)/ C[1],bar) > .2 orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > .2 orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > .2 orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > .2 orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > .2 ), bar) < 0 ) 14 * ( Sum( ( HHV((C[1]  C)/ C[1],bar) > .15 orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > .15 orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > .15 orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > .15 orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > .15 ), bar) < 0 ) 9 * ( Sum( ( HHV((C[1]  C)/ C[1],bar) > .1 orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > .1 orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > .1 orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > .1 orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > .1 ), bar) < 0 ) 4 * ( Sum( ( HHV((C[1]  C)/ C[1],bar) > .05 orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > .05 orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > .05 orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > .05 orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > .05 ), bar) < 0 ) Thread moved by JimDean on 8/4/2014 8:49 AM from Markets & Methods > OmniVest, Money Mgmt & Risk Control > OScript for CAR, MDD, and Calmar Ratio  
JimDean 
 
Owner/Admin Posts: 3886 Location: USA: GA, Lawrenceville  Pulling all this together ... Calmar Ratio = CAR / MDD ... so, using the nifty, clean little CAR formula from the first post as the numerator, and the brontosaurian MDD formula from the prior post as the denominator, we get: 100*( ( C/C[bar] ) ^ ( 1/ (bar/252) ) 1 ) / ( 1 19 * ( Sum( ( HHV((C[1]  C)/ C[1],bar) > .2 orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > .2 orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > .2 orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > .2 orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > .2 ), bar) < 0 ) 14 * ( Sum( ( HHV((C[1]  C)/ C[1],bar) > .15 orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > .15 orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > .15 orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > .15 orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > .15 ), bar) < 0 ) 9 * ( Sum( ( HHV((C[1]  C)/ C[1],bar) > .1 orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > .1 orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > .1 orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > .1 orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > .1 ), bar) < 0 ) 4 * ( Sum( ( HHV((C[1]  C)/ C[1],bar) > .05 orelse (HHV(C,2)[1]  C) / HHV(C,2)[1] > .05 orelse (HHV(C,3)[1]  C) / HHV(C,3)[1] > .05 orelse (HHV(C,4)[1]  C) / HHV(C,4)[1] > .05 orelse (HHV(C,5)[1]  C) / HHV(C,5)[1] > .05 ), bar) < 0 ) ) Keep in mind that the formula is giving an MDD approximation of 1,5,10,15,20. You could of course make it more precise by extending the MDD formula to have more "bins". Also you could extend the MDD formula to cover a bigger gap than just the six days that this one does. I have checked the syntax of all these formulae, via OScan. But I've not tried them out yet in an OVest condition. If any of you have time to (mine is fully run out for today!), please post your results here. Have fun! Thread moved by JimDean on 8/4/2014 8:49 AM from Markets & Methods > OmniVest, Money Mgmt & Risk Control > OScript for CAR, MDD, and Calmar Ratio  
JimDean 
 
Owner/Admin Posts: 3886 Location: USA: GA, Lawrenceville  I've found out something from Barry since posting earlier. The "window" over which the OScript is calc'd is ALWAYS the full history ... it ignores the Account settings "start date" entry. It also includes some unknown number of warmup bars, before 1/1/2000 ... which may or may not affect the MDD & CAR & CALMAR calc's depending on whether the "Equity C" is populated before the 1/1/2000 officialhistory start date. So, every time you run these formulae, they will be for the period of 1/1/2000 (or before), up through whatever bar is being processed. If you want to LIMIT the range of the calc's to a LATER start date, then you need to SUBTRACT some integer from "bar" wherever it's used in the formulae. That is, replace "bar" in the formulae with (barNM), where: N = bars (ie days) between your desired start date, and 1/1/2000 M = whatever number of warmup bars OVest is using (I'll report later what Barry tells me about this) So, if you wanted to start your MDD or CAR or CALMAR analysis as of 1/1/2007, there are a total of six years before that since 1/1/2000, and each year has about 252 trading days, so N = 6*252 = 1512. If your test period starts on 1/1/2013, N would be 12 years = 3024. Thread moved by JimDean on 8/4/2014 8:49 AM from Markets & Methods > OmniVest, Money Mgmt & Risk Control > OScript for CAR, MDD, and Calmar Ratio  
JohnWolfraad 
 
Veteran Posts: 208 Location: Australia: , Church Point, NSW  Don't know if this is part of the answer, but if you click on a strategy and look at the detail it says an "Inception" right under the Strategy Info and Statistics. All the ones I've looked at so far are 1/1/1970 Thread moved by JimDean on 8/4/2014 8:49 AM from Markets & Methods > OmniVest, Money Mgmt & Risk Control > OScript for CAR, MDD, and Calmar Ratio  
JimDean 
 
Owner/Admin Posts: 3886 Location: USA: GA, Lawrenceville  I noticed the "1970", but my guess is that it's just a placeholder. Except for a few indexes, afaik OmniData only goes back to about 1990. Ten years of warmup would be absurdly long  so I doubt that the full depth of history is being used. Otoh, if they are doing it that way, that could explain the long delays! In order to correct the formula, we need the explicit "M" value. I hope that Barry will provide a bit more detail. He told me that eventually Cose will modify the calc to recognize and use the input Starting Date for OScripts. However, that will necessitate a warmup period too (for the OScript formula). This is not a clean fix kinda thing. Furthermore  some symbols have data inception AFTER the 1/1/2000 date. When OScript formulae are applied to those symbols (some very popular ones), then there is currently no warmup. You can code a warmup delay of you use OLang but not via OScript. Note that unwarmedup OScript filters still do "work"  but they don't work in the same manner as they would have at the HRE. The issue with the MDD, CAR and CALMAR calc's is not that they need warmup but rather, any warmup period that they are acting upon might yield false trade info. I'm also waiting on an answer about that, from Barry. Thread moved by JimDean on 8/4/2014 8:49 AM from Markets & Methods > OmniVest, Money Mgmt & Risk Control > OScript for CAR, MDD, and Calmar Ratio  
SteveLuerman 
 
Elite Posts: 409 Location: USA: CO, Boulder  Comment on the reason for 1/1/1970: That's day zero in Unix time. See http://en.wikipedia.org/wiki/Unix_time So, as Jim stated, it is probably a placeholder which is set to 0. Thread moved by JimDean on 8/4/2014 8:49 AM from Markets & Methods > OmniVest, Money Mgmt & Risk Control > OScript for CAR, MDD, and Calmar Ratio  
JimDean 
 
Owner/Admin Posts: 3886 Location: USA: GA, Lawrenceville  I got some more info from Barry today ... it corrects some of the things he alluded to earlier ... 1. OVest Data is NOT going back as far as OmniData EOD provides. 2. OVest OScripts are using the number of calendar days between 1/1/2000 and today, and no further. ** They are looking into having 1/1/1999 as the earliest start date for data, trading, & VBA conditions with 1/1/2000 being earliest “visible” start date for OmniVest users. 3. Equity "C" dataseries has "trades" in it prior to 2000, but Oscript calculations only go back to 1/1/2000. 4. Is there any provision for OScript warmup when for example an ema(200) is used in a script for a symbol whose history only goes back to 2007. Note that an ema requires at least 35x Periods of warmup, to be even somewhat legit. 4. OVest OScripts do not automatically account for any specific warmup requirements. In the case of ema(200) it will give valid values starting with the 201 bar from the beginning of the data set. *** Jim's note ... ALL EMA's and many other derivative indicators require more than just the core# periods to "warm up". A Nirvana EMA(200) does produce values after the first 200 bars ... but those initial values are essentially just SMA's not EMA's. There can be a big difference. An EMA needs 35x periods of warmup, not just 1x. Thread moved by JimDean on 8/4/2014 8:49 AM from Markets & Methods > OmniVest, Money Mgmt & Risk Control > OScript for CAR, MDD, and Calmar Ratio  
JimDean 
 
Owner/Admin Posts: 3886 Location: USA: GA, Lawrenceville  For some purposes such as position sizing or liquidity analysis (nothing to do with this thread, really), since OVest does not provide the Equity dataseries to OScript, it can be helpful to be able to calculate the "Anticipated Equity" (AE) for each bar moving forward, given a particular starting Equity AND whatever you might consider to be a "minimum acceptable" CAR (CARma? ;~). Using algebra on the CAR formulae in the first post yields: ((%CAR/100 + 1) ^Years) * Initial = Final ... or, in OScript, for a given bar in the historical range ... Equity@bar = ((%CAR/100 + 1) ^(bar/252)) * Equity@Start Important: that formula presumes that "bar0" corresponds to the beginning of the period that the DynList is being used. Currently, Barry reports that bar0 for OmniScripts in OVest starts at the beginning of 2000. He says that Cose is planning to change that, to tie it to the Account Settings simulation range instead. Until that modification is made, you can adapt the formula for the range of bars you are working with, thus: Equity@bar = ((%CAR/100 + 1) ^((barStartOfRangeBar#)/252)) * Equity@StartOfRange I will be using this "Equity as you go" concept as part of the free presentation that I will be making in Austin at the Bash hotel, this Saturday afternoon ... please email me if ASAP you want to join us (1p5:30p). Thread moved by JimDean on 8/4/2014 8:49 AM from Markets & Methods > OmniVest, Money Mgmt & Risk Control > OScript for CAR, MDD, and Calmar Ratio  

Owner of site: Jim Dean  Forum content is confidential, and may not be distributed without written permission.  