Arrow Point White Tracking
Leveraging the Amibroker data feed, Arrow Point White Tracking becomes a pivotal tool for pinpointing potential entry and exit points. Integrating this into an Amibroker AFL ensures a systematic approach to identifying trend reversals or continuations, aiding traders in making informed decisions based on these precise indicators.
//* P_LRS_06a.afl Progster's AFL skeleton for LRS-based trading strategy. This strategy models 4 relevant indicator levels: Low level on the indicator (i.e weakness, oversold) High level on the indicator (i.e strength, overbought) Long Exit (LX) level on the indicator (for optional indicator-based long trade profit-taking) Short Exit (SX) level on the indicator (for optional indicator-based short trade profit-taking) For optimization, there are 8 major numeric dimensions: LRS_Base_Period LRS_Smooth_Period LRS_LowLvl LRS_HighLvl LX_Above_Lvl SX_Below_Lvl StopLossPct PftTgtPct TrailStopPct along with various switches and choices: TradingMode SignalType FilterType LongShortBoth InvertSignals SingleContract DayTrade Settings This strategy is designed to allow wide-scope or narrow-scope optimization to be configured from the AB Parameters Dialog. This means optimization across any combination of the major numeric dimensions based strictly on Dialog settings, without requiring code edits. SO, IN GENERAL, YOU WILL NOT NEED TO EDIT THE CODE TO SCOPE YOUR OPTIMIZATION. However, not every single parameter is so configured. Any desired changes can be made once the code has been studied and understood. This code implements single contract/share next-bar-on-open testing and visualization (when TradingMode = 1). This is only one of many ways AmiBroker can trade, but it is the most important and natural way to model (IMO), and is also consistent with many other platforms. Note: Certain abbreviations have been carefully chosen to support textual substitution and avoid various incompatibilities (with keywords, with IO, and others). Best all-around results will be obtained by understanding and respecting these conventions in any further edits. "Vary" is used to indicate where opt-im-iz-ation may be taking place. Likewise for"OType". "Parm" is used instead of par-am-eter. To generate a feature list from the Windows command line (if grep is installed): grep "\*\*\*\*\*" P_LRS_06a.afl Code for setup of cooperating indicator Code for adding custom metric(s) Code for AA window display of non-optimized parameters Code for optimizer choice and setup Code for single contract testing Code for choosing a Trading Mode ( entries/exits, on-Open/on-Close ) Code for technical analysis calculation(s). Code for trading long-only, short-only, or in both directions Code for trading signals in the opposite direction Code for a choice of trade signal filters Code for limiting trading to an intraday time window Code for optimizable indicator-based exits Code for optimizable StopLoss and PftTgt Code for determining and displaying exit reason Code for histogram visualization of buy/sell/short/cover arrays. Code for passing NetPft to cooperating display indicator in another chart pane. Code for Displaying signals as an Exploration Code for on-chart plotting of price, signal arrows, and trade duration/direction bar coloring Code for creating and displaying informative title text Code for display of filters In the parameters dialog, leading "+++++++" indicates a "Use" switch, which turns a block of functionality On/Off. In the parameters dialog, trailing "----------" indicates a "Vary" switch, which turns just opt-im-iz-ation On/Off. When altering or extending this strategy, to keep all intended functionality, visit every line containing "###" and make edits as/if necessary in accord with the instructions. Regarding use with IO: As of this writing, it is not possible to have built-in AB optimizer choice features and use of IO from the same file. However, every effort has been made to minimize the required differences. Search on "non-IO" to find the 3 instructions (###) regarding changes for use with/without IO. Author's note: This code is the result of years of background experience, months of general investigation, and weeks of specific research, design, coding, and testing. By beginning with this code, you get to avoid _alot_ of trial and error. If what you see here seems clear and obvious upon reading, that is the hoped-for intent. However, getting to this point has been a both a journey and a labor. This code is provided in return for a fee, which is relied upon for part of my livelihood. Knowing the time/effort spent to produce it, I can assure you that this code is a deep-bargain-at-the-price (that's my business model). However, YMMV. This code is not freeware, or trialware. This code is a professionally produced commercial product, and you must purchase a license in order to use it or possess it. If you are in posession of this code without having paid, you must either go to CodeForTraders.com and pay the asking price, or else delete it immediately. Caveats and Support Policy: http://www.codefortraders.com/Caveats.htm http://www.codefortraders.com/Customer_Support.htm Further extension/alteration/customization of this code is available on a for-hire, time-available basis to licensed users. CodeForTraders.com also offers ecommerce services to AmiBroker developers (i.e. earn by selling your high-quality AB code). Inquiries: progster@CodeForTraders.com Thanks to Tomasz Janeczko for AmiBroker, and to the many in the AB community who have documented and coded for AB before me. This code builds on everything I could find and absorb so far. Hopefully, this code will help you to shorten your journey, and lighten your labor ... Enjoy! - Progster */ // Copyright 2009 by Steve Johns, aka Progster, all rights reserved, worldwide. // Exclusive distribution by CodeForTraders.com. Other distribution prohibited. _SECTION_BEGIN("P_LRS_06a.afl"); /* function ParmVary( ParamTitle, defaultVal, minv, maxv, step ) { return Optimize( ParamTitle, Param( ParamTitle, defaultVal, minv, maxv, step ), minv, maxv, step ); } // New function by Progster, 4/20/2009 // ParmChoiceVary() allows you a choice to "lock down" or "vary" a parameter at optimization runtime. // To get the desired effect, this function must be called unconiditonally from the top level. // i.e. do not call from inside an if(){} block. // --- Unacceptable to IO: "Non-numeric <> value in Optimize Statement" --- function ParmChoiceVary( Mode, ParmTitle, defaultVal, minv, maxv, step ) { retval = 0 ; if (Mode) { retval = Optimize( ParmTitle, Param( ParmTitle, defaultVal, minv, maxv, step ), minv, maxv, step ) ; } else { retval = Param( ParmTitle, defaultVal, minv, maxv, step ) ; } return retval ; } */ // Transform DateNum (e.g., 1040928 or 921114) to String mmddyyyy (e.g., 09/28/2004 or 11/14/1992) // From the AFL Library: http://www.amibroker.com/library/detail.php?id=415 // function DateToStr(nDate) { //if you want string without separators you have to specify this in your //NumToStr call http://www.amibroker.com/f?numtostr //string=NumToStr(SelectedValue(nDate),1,False); //You can use StrFormat for more control http://www.amibroker.com/f?strformat string = StrFormat("%7.07g", nDate); //extract string part yy = StrLeft(string, 3); mm = StrMid(string, 3, 2); dd = StrRight(string, 2); //transform year yy = StrToNum(yy) + 1900; //CORRECT BEFORE AND AFTER 2000 //return string return mm + "/" + dd + "/" + NumToStr(yy, 1, False); } // ******************** Start of: parameters.afl ******************** // ----- Strategy-specific Default parameter values // All default values for parameters are assigned to variables here. // The variables will be used as defaultVal arguments elsewhere so as not to be hard-coded . // This entire block may be separated into an include file if desired, // which will likely be the case when implementing advanced external control of AB // for large scale test definition and replication. // Suffixes: _0 numeric setting, _I0 toggle or list setting Vary_SignalType_0 = 0 ; Vary_FilterType_0 = 0 ; Vary_TradingMode_0 = 0 ; SignalType_0 = 1 ; FilterType_0 = 0 ; TradingMode_0 = 1 ; Vary_LRS_Base_Period_0 = 1 ; Vary_LRS_Smooth_Period_0 = 1 ; LRS_Base_Period_0 = 2 ; LRS_Smooth_Period_0 = 3 ; Vary_LRS_LowLvl_0 = 1 ; Vary_LRS_HighLvl_0 = 1 ; LRS_LowLvl_0 = -.5 ; LRS_HighLvl_0 = .5 ; LongShortBoth_0 = 3 ; InvertSignals_I0 = 0 ; SingleContract_I0 = 1 ; ExploreType_I0 = 1 ; ExtraDecimals_I0 = 0 ; EquitySend_0 = 1 ; UseIndLvlExits_I0 = 1; Vary_LX_Above_Lvl_I0 = 1 ; Vary_SX_Below_Lvl_I0 = 1 ; LX_Above_Lvl_0 = .4 ; SX_Below_Lvl_0 = -.4 ; UseStopsAndTgts_I0 = 1 ; VaryStops_I0 = 0; // hold constant VaryTgts_I0 = 0; // hold constant VaryTrailStop_I0 = 0; // hold constant StopLossPct_0 = 1 ; PftTgtPct_0 = 5 ; TrailStopPct_0 = 20; DaytradeOnly_I0 = 0 ; // No, allow overnight trades NoEntriesBefore_0 = 930 ; ExitAllTime_0 = 1550 ; NoEntriesAfter_0 = 1530 ; OType_I0 = 1 ; // 1-3: "CMAE|Tribes|SPSO" VaryRuns_0 = 2 ; VaryMaxEval_0 = 200 ; CustomMetrics_I0 = 1 ; ShowSignalsHistogram_I0 = 1 ; // ----- end of: Default parameter values // ******************** End of: parameters.afl ******************** // ### Comment out this block when not doing parameter substitution via batch automation // ### Note: This inclusion is only appropriate for non-IO use. // printf( "Included: \n" ) ; // #include // override the settings above (e.g. for batch automation) /* The OptIterReload file is used to overwrite the formula parameter defaults with a different set of initial values, generally a set that was written out by Progster's Excel VB macro 'AB_Opt_Params_Export()'. IOW, the parameters used for a specific optimizer iteration may now be reloaded without manual typing! Here is the process (in short): 1. Perform an optimization and save the optimization results spreadsheet (automatically or manually). 2. Open the spreadsheet in Excel, select a one-row region of parameters (for the iteration of interest). 3. Use Alt-F8, and run Progster's VBA macro 'AB_Opt_Params_Export()'. 4. Verify the path to which you wish the output file (OptIterReload_0.afl) to be written, then press OK. The file 'OptIterReload_0.afl' will be written to your chosen location. It will contain AFL to (re)define each of your selected parameter values as per the spreadsheet. IOW, as per that particular optimization iteration. By including this file here, we set the parameter defaults values to same. 5. Open the AB parameters dialog and press the 'Reset' button. Your parameters are now set as desired. The above works for both chart loading and backtest loading. Therefore, it is now possible to quickly and easily view/evaluate _all_ the pertinent info for _any_ iteration of any optimization. Note: It is possible that the spreadsheet will not contain a column for every operative parameter. When comparing "reload" results to an optimization interation line, beware the effects of unrepresented parameters. Note: because we are including this file, it must be present for this AFL to run. However, it is OK for the file to be empty. So, until you've generated a "real" OptIterReload_0.afl, just make sure there is an empty one at the include location. Alternatively, just comment out the include line (which disables this functionality). */ // ### Note: This inclusion is only appropriate for non-IO use. // printf( "Included: " ) ; // #include_once // overrides defaults set in parameters.afl // ----- Code for Setup/Configuration // Intialize any variables/arrays which should never be undefined NetPft = 0; UsingIO = 0 ; LRS_ScaleFactor = 1 ; // normally 10k for FX, 1 for stocks and futures // These seem to be necessary for IO (?) TradingMode = 1 ; BuyDelay = SellDelay = ShortDelay = CoverDelay = 1 ; // ### Name the indicator(s) in use. This name will be used in many places. EnableTextOutput(False); Formula_Name = "P_LRS_06a" ; LRS_Name = "LRS" ; EnableTextOutput(True); sp2 = " "; // two spaces, used for indenting grouped parameters // Label the list parameters shown in the Interpretation window. // Comment this out if ParamList() is NOT present anywhere below, // or if every instance of it has been suppressed by wrapping with // EnableTextOutput(False); EnableTextOutput(True); // printf( "List Parameter Choices: \n") ; // This works if you want to use a different price than Close (but no optimization provided) //BasePrice = ParamField("BasePrice", 3) ; //BasePricePlotStyle = ParamList("BasePricePlotStyle", "Line|NoPlot", 1); // Parameter definitions. // In this formula, parameters are grouped at the top and ordered for sensible display in the Parameter dialog. // An alternative (not done here), is to place parameter definitions throughout the file near the code that uses them. // Note: This construction fails in IO. The brackets _must not_ be on the same line . /* if (Vary_RSI_Smooth_Period) { RSI_Smooth_Period = Optimize( RSI_Name + "_Smooth_Period", RSI_Smooth_Period_Param, 1, 20, 1) ; } else { RSI_Smooth_Period = RSI_Smooth_Period_Param ; } */ // Master switch for using or not using IO - intended to control subsequent includes. Not currently operational. // UsingIO = ParamToggle( "UsingIO", "No|Yes", 1); // Show the user that he is using IO, but offer no choice. // ### Comment these out for non-IO use. For use with IO, uncomment these lines. // UsingIO = ParamToggle( "UsingIO (No Opt Engine Choice)", "Yes|Yes", 0); // UsingIO = 1 ; // IO needs to know about your #include directory, if you are including files // You should be able to tell it in 'AmiBroker\IO\IO Defaults.txt'. But if not, tell it here. ////IO: IncludeDir: c:\AmiBroker_Formula_Root\Include // Conceptually, this is what we want, but AB does not allow for conditional #include // if (! UsingIO) { #include } // ### Uncomment this for non-IO use. For use with IO, comment this out. // #include // contents reproduced below // ******************** Start of: OptOptionChoices.afl ******************** /* When _NOT_ using IO, offer a choice of the AmiBroker built-in optimizers, and their settings. If using IO, this choice should not be, and is not, offered. UsingIO should be set in the file which is including this one. */ printf( "Included: OptOptionChoices.afl" ) ; printf( "\n" ) ; // print blank line to Interpretation window for visual spacing if (UsingIO){ } else{ // Pointless and dangerous when using IO OType = ParamList("---- OType", "Exhaustive|CMAE|Tribes|SPSO", OType_I0); // default: CMAE, (Note: "OType" instead of "Opti-mizerType" for IO compatibility) VaryRuns = Param( "---- VaryRuns", VaryRuns_0, 0, 10, 1); VaryMaxEval = Param( "---- VaryMaxEval", VaryMaxEval_0, 0, 10000, 1); if (OType == "Exhaustive"){ VaryRuns = 0; VaryMaxEval = 0; } } // ******************** End of: OptOptionChoices.afl ******************** PlotRawPrice = ParamToggle( "Plot Raw Price", "No|Yes", 1 ); // RawPricePlotStyle = ParamList("RawPricePlotStyle", "Line|NoPlot", 1); PricePlotStyle = ParamStyle("PricePlotStyle", styleBar, maskPrice); PlotEntryArrows = ParamToggle( "PlotEntryArrows", "No|Yes", 1 ); PlotExitArrows = ParamToggle( "PlotExitArrows", "No|Yes", 1 ); Vary_TradingMode = ParamToggle( "Vary Trading Mode ---------- ", "No|Yes", Vary_TradingMode_0 ); // default No TradingMode_Param = Param( "TradingMode", TradingMode_0, 1, 4, 1) ; if (Vary_TradingMode){ TradingMode = Optimize( "TradingMode", TradingMode_Param, 1, 4, 1) ; } else{ TradingMode = TradingMode_Param ; } Vary_SignalType = ParamToggle( "Vary Signal Type ---------- ", "No|Yes", Vary_SignalType_0 ); // default No SignalType_Param = Param( "SignalType", SignalType_0, 1, 2, 1) ; if (Vary_SignalType){ SignalType = Optimize( "SignalType", SignalType_Param, 1, 2, 1) ; } else{ SignalType = SignalType_Param ; } Vary_FilterType = ParamToggle( "Vary Filter Type ---------- ", "No|Yes", Vary_FilterType_0 ); // default No FilterType_Param = Param( "FilterType", FilterType_0, 0, 2, 1) ; if (Vary_FilterType){ FilterType = Optimize( "FilterType", FilterType_Param, 0, 2, 1) ; } else{ FilterType = FilterType_Param ; } Vary_LRS_Base_Period = ParamToggle( "Vary Base Period ---------- ", "No|Yes", Vary_LRS_Base_Period_0 ); // default Yes LRS_Base_Period_Param = Param( LRS_Name + "_Base_Period", LRS_Base_Period_0, 2, 50, 1) ; if (Vary_LRS_Base_Period){ LRS_Base_Period = Optimize( LRS_Name + "_Base_Period", LRS_Base_Period_Param, 2, 50, 1) ; } else{ LRS_Base_Period = LRS_Base_Period_Param ; } Vary_LRS_Smooth_Period = ParamToggle( "Vary Smooth_Period ---------- ", "No|Yes", Vary_LRS_Smooth_Period_0 ); // default Yes LRS_Smooth_Period_Param = Param( LRS_Name + "_Smooth_Period", LRS_Smooth_Period_0, 1, 20, 1) ; if (Vary_LRS_Smooth_Period) { LRS_Smooth_Period = Optimize( LRS_Name + "_Smooth_Period", LRS_Smooth_Period_Param, 1, 20, 1) ; } else{ LRS_Smooth_Period = LRS_Smooth_Period_Param ; } Vary_LRS_LowLvl = ParamToggle( "Vary Low Level ---------- ", "No|Yes", Vary_LRS_LowLvl_0 ); // default Yes LRS_LowLvl_Param = Param( LRS_Name + "_LowLvl", LRS_LowLvl_0, -10, 0, .1) ; if (Vary_LRS_LowLvl){ LRS_LowLvl = Optimize( LRS_Name + "_LowLvl", LRS_LowLvl_Param, -10, 0, .1) ; } else{ LRS_LowLvl = LRS_LowLvl_Param ; } Vary_LRS_HighLvl = ParamToggle( "Vary High Level ---------- ", "No|Yes", Vary_LRS_HighLvl_0 ); // default Yes LRS_HighLvl_Param = Param( LRS_Name + "_HighLvl", LRS_HighLvl_0, 0, 10, .1) ; if (Vary_LRS_HighLvl){ LRS_HighLvl = Optimize( LRS_Name + "_HighLvl", LRS_HighLvl_Param, 0, 10, .1) ; } else{ LRS_HighLvl = LRS_HighLvl_Param ; } LongShortBoth = Param( "LongShortBoth", LongShortBoth_0, 1, 3, 1 ); // 3 iterations InvertSignals = ParamToggle( "InvertSignals", "No|Yes", InvertSignals_I0 ); SingleContract = ParamToggle( "SingleContract", "No|Yes", SingleContract_I0 ); EnableTextOutput(False); ExploreType = ParamList("ExploreType", "Current|Today|Historical", ExploreType_I0); EnableTextOutput(True); ExtraDecimals = ParamToggle( "ExtraDecimals", "No|Yes", ExtraDecimals_I0 ); LRS_ScaleFactor = Param("LRS_ScaleFactor", 1, 1, 10000, 100 ); // coordinate with indicator receiver pane EquitySend = Param("EquitySend", EquitySend_0, 0, 10, 1); // coordinate with NetPft receiver pane, 0 means no send // Optional Indicator-level exits // Note that both Use AND Vary settings are passed to ParmChoiceVary() for the desired effect. UseIndLvlExits = ParamToggle( "+++++++ UseIndLvlExits", "No|Yes", UseIndLvlExits_I0 ); // default Yes Vary_LX_Above_Lvl = ParamToggle( sp2 + "Vary LX Above Level ---------- ", "No|Yes", Vary_LX_Above_Lvl_I0 ); // default Yes LX_Above_Lvl_Param = Param( sp2 + "LX_Above_Lvl", LX_Above_Lvl_0, 0, 10, .1) ; // Long Exit indicator level if ((UseIndLvlExits != 0) AND (Vary_LX_Above_Lvl != 0)){ LX_Above_Lvl = Optimize( sp2 + "LX_Above_Lvl", LX_Above_Lvl_Param, 0, 10, .1) ; // Long Exit indicator level } else{ LX_Above_Lvl = LX_Above_Lvl_Param ; } Vary_SX_Below_Lvl = ParamToggle( sp2 + "Vary SX Below Level ---------- ", "No|Yes", Vary_SX_Below_Lvl_I0 ); // default Yes SX_Below_Lvl_Param = Param( sp2 + "SX_Below_Lvl", SX_Below_Lvl_0, -10, 0, .1) ; // Short Exit indicator level if ((UseIndLvlExits != 0) AND (Vary_SX_Below_Lvl != 0)){ SX_Below_Lvl = Optimize( sp2 + "SX_Below_Lvl", SX_Below_Lvl_Param, -10, 0, .1) ;// Short Exit indicator level } else{ SX_Below_Lvl = SX_Below_Lvl_Param ; } // Optional stop-loss and profit target exits. UseStopsAndTgts = ParamToggle( "+++++++ UseStopsAndTgts", "No|Yes", UseStopsAndTgts_I0 ); // default Yes, which displays/uses Stops. If No, all stops disabled VaryStops = ParamToggle( sp2 + "Vary Stops ---------- ", "No|Yes", VaryStops_I0 ); // default Yes StopLossPct_Param = Param( sp2 + "StopLossPct", StopLossPct_0, 0, 20, .01 ); // optimize or set stop loss if ((UseStopsAndTgts != 0) AND (VaryStops != 0)){ StopLossPct = Optimize( sp2 + "StopLossPct", StopLossPct_Param, 0, 20, .01 ); // optimized stop loss } else{ StopLossPct = StopLossPct_Param ; } VaryTgts = ParamToggle( sp2 + "Vary Targets ---------- ", "No|Yes", VaryTgts_I0 ); // default Yes PftTgtPct_Param = Param( sp2 + "PftTgtPct", PftTgtPct_0, 0, 50, .01 ); // optimized profit target if ((UseStopsAndTgts != 0) AND (VaryTgts != 0)){ PftTgtPct = Optimize( sp2 + "PftTgtPct", PftTgtPct_Param, 0, 50, .01 ); // optimized profit target } else{ PftTgtPct = PftTgtPct_Param ; } VaryTrailStop = ParamToggle( sp2 + "Vary TrailStop ---------- ", "No|Yes", VaryTrailStop_I0 ); // default Yes TrailStopPct_Param = Param( sp2 + "TrailStopPct", TrailStopPct_0, 0, 20, .01 ); // optimize or set trail stop if ((UseStopsAndTgts != 0) AND (VaryTrailStop != 0)){ TrailStopPct = Optimize( sp2 + "TrailStopPct", TrailStopPct_Param, 0, 20, .01 ); // optimized trail stop } else{ TrailStopPct = TrailStopPct_Param ; } CustomMetrics = ParamToggle( "CustomMetrics", "No|Yes", CustomMetrics_I0 ); ShowSignalsHistogram = ParamToggle( "ShowSignalsHistogram", "No|Yes", ShowSignalsHistogram_I0 ); DaytradeOnly = ParamToggle("+++++++ DaytradeOnly", "No|Yes", DaytradeOnly_I0); NoEntriesBefore = Param(sp2 + "NoEntriesBefore", NoEntriesBefore_0, 930, 1559, 5); ExitAllTime = Param(sp2 + "ExitAllTime", ExitAllTime_0, 930, 1559, 5); NoEntriesAfter = Param(sp2 + "NoEntriesAfter", NoEntriesAfter_0, 930, 1559, 5); printf( "\n") ; // output blank line after list parameter choices // ***** Code for setup of cooperating indicator // Send parameter settings to the cooperating indicator // Example: rLRS.p1.afl // ### Create any new settings as necessary StaticVarSet(LRS_Name + "_Length", LRS_Base_Period); StaticVarSet(LRS_Name + "_Smooth", LRS_Smooth_Period); StaticVarSet(LRS_Name + "_LowLvl", LRS_LowLvl); StaticVarSet(LRS_Name + "_HighLvl", LRS_HighLvl); StaticVarSet(LRS_Name + "_LX_Above_Lvl", LX_Above_Lvl); StaticVarSet(LRS_Name + "_SX_Below_Lvl", SX_Below_Lvl); StaticVarSet(LRS_Name + "_LRS_ScaleFactor", LRS_ScaleFactor); // ***** Code for adding custom metric(s) // This is a skeleton (with demos). // Add your own desired custom metrics in this block. if(CustomMetrics){ SetOption("UseCustomBacktestProc", True ); // Enable custom backtest procedure SetCustomBacktestProc("", 1); // "" means use current formula if( Status("action") == actionPortfolio ){ bo = GetBacktesterObject(); // retrieve the interface to portfolio backtester // bo.Backtest( False ); // run default backtest procedure (generating a trade list) bo.Backtest( True ); // run default backtest procedure (don't generate a trade list) // Custom trade metrics (on closed trade list) for( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() ) // iterate over closed trade list // for( openpos = bo.GetFirstOpenPos(); openpos; openpos = bo.GetNextOpenPos() ) // iterate over open position list { // trade variable now holds Trade object // Calculate trade-level custom metric(s) NetChg = trade.ExitPrice - trade.EntryPrice ; // Add trade-level custom metric(s) to the backtest report trade.AddCustomMetric( "NetChg", NetChg ); } bo.ListTrades(); // NOW generate the trades list (after adding custom trade metric(s) stats = bo.GetPerformanceStats(0); // get stats for all trades // Expectancy calculations (two versions, same result). // See: Porfolio Backtester Interface Reference Guide //exp1 = stats.GetValue("WinnersAvgProfit")*stats.GetValue("WinnersPercent")/100 + stats.GetValue("LosersAvgLoss")*stats.GetValue("LosersPercent")/100; exp2 = stats.GetValue("NetProfit")/ (stats.GetValue("WinnersQty") + stats.GetValue("LosersQty")) ; // Add portfolio-level custom metric(s) to the optimization report // bo.AddCustomMetric( "Exp1 ($)", exp1 ); bo.AddCustomMetric( "Exp2 ($)", exp2 ); // ***** Code for AA window display of non-varied parameters // Add non-varied parameters as custom metrics. // This let's you see in the output which fixed parm values were used. // The AA window automatically displays columns for parms being varied, so the intent here is to // only create custom metric columns for the parms which ARE NOT being varied. // ### In general, make sure all non-varied parms are present here. // ### Abbreviations are used in some places for column titles. Change if desired. // _TRACE( "UseStopsAndTgts: " + NumToStr( UseStopsAndTgts ) ) ; // Group Control sub-item metric definition // is ON not being varied if ((UseIndLvlExits != 0) AND (Vary_LX_Above_Lvl == 0)) { bo.AddCustomMetric( "LX_Above_Lvl", LX_Above_Lvl ); } if ((UseIndLvlExits != 0) AND (Vary_SX_Below_Lvl == 0)) { bo.AddCustomMetric( "SX_Below_Lvl", SX_Below_Lvl ); } if ((UseStopsAndTgts != 0) AND (VaryStops == 0)) { bo.AddCustomMetric( "StopLossPct", StopLossPct ); } if ((UseStopsAndTgts != 0) AND (VaryTgts == 0)) { bo.AddCustomMetric( "PftTgtPct", PftTgtPct ); } // if (( != 0) AND ( != 0)) { bo.AddCustomMetric( "", ); } // Single Control metric definition if (Vary_TradingMode == 0) { bo.AddCustomMetric( "Mode", TradingMode, TradingMode, TradingMode, 0); } if (Vary_SignalType == 0) { bo.AddCustomMetric( "Signal", SignalType, SignalType, SignalType, 0); } if (Vary_FilterType == 0) { bo.AddCustomMetric( "Filter", FilterType, FilterType, FilterType, 0); } if (Vary_LRS_Base_Period == 0) { bo.AddCustomMetric( LRS_Name + "_Base_Period", LRS_Base_Period ); } if (Vary_LRS_Smooth_Period == 0) { bo.AddCustomMetric( LRS_Name + "_Smooth_Period", LRS_Smooth_Period ); } if (Vary_LRS_LowLvl == 0) { bo.AddCustomMetric( LRS_Name + "_LowLvl", LRS_LowLvl ); } if (Vary_LRS_HighLvl == 0) { bo.AddCustomMetric( LRS_Name + "_HighLvl", LRS_HighLvl ); } if ((UsingIO != 1) AND (VaryRuns != 0)) { bo.AddCustomMetric( "VaryRuns", VaryRuns ); } if ((UsingIO != 1) AND (VaryMaxEval != 0)) { bo.AddCustomMetric( "VaryMaxEval", VaryMaxEval ); } // Non-optimized Toggles - always report when relevant bo.AddCustomMetric( "LSB", LongShortBoth, LongShortBoth, LongShortBoth, DecPlaces = 0); bo.AddCustomMetric( "Invert", InvertSignals, InvertSignals, InvertSignals, DecPlaces = 0); bo.AddCustomMetric( "UseIndLvlExits", UseIndLvlExits, UseIndLvlExits, UseIndLvlExits, DecPlaces = 0); bo.AddCustomMetric( "UseStopsAndTgts", UseStopsAndTgts, UseStopsAndTgts, UseStopsAndTgts, DecPlaces = 0); if (UsingIO != 1) { bo.AddCustomMetric( "OType", OType, OType, OType, DecPlaces = 0); } if (LRS_ScaleFactor != 1) { bo.AddCustomMetric( "LRS_ScaleFactor", LRS_ScaleFactor, LRS_ScaleFactor, LRS_ScaleFactor, DecPlaces = 0); } // Daytrade Settings bo.AddCustomMetric( "DaytradeOnly", DaytradeOnly, DaytradeOnly, DaytradeOnly, DecPlaces = 0); bo.AddCustomMetric( "NoEntriesBefore", NoEntriesBefore, NoEntriesBefore, NoEntriesBefore, DecPlaces = 0); bo.AddCustomMetric( "ExitAllTime", ExitAllTime, ExitAllTime, ExitAllTime, DecPlaces = 0); bo.AddCustomMetric( "NoEntriesAfter", NoEntriesAfter, NoEntriesAfter, NoEntriesAfter, DecPlaces = 0); // if ( == 0) { bo.AddCustomMetric( "", ); } } // end of: if( Status("action") == actionPortfolio ) } // end of: if(CustomMetrics) // Conceptually, this is what we want, but AB does not allow for conditional #include // if (! UsingIO) { #include } // ### Uncomment this for non-IO use. For use with IO, comment out this line. // ### Comment this out if you prefer your extra columns (parms) at the end rather than in front // ### Also, comment this out if not running in AB 5.23 or later ! SetOption("ExtraColumnsLocation", 1 ); // put parameter columns up-front after optimization // ***** Code for single contract testing if (SingleContract) PositionSize = MarginDeposit = 1; // Trade a single contract. // ***** Code for choosing a Trading Mode ( entries/exits, on-Open/on-Close ) /* TradingMode = 1 (the default, as supplied) Trade on the Open of the next bar after a Signal. This requires setting the trade price arrays to Open, AND setting the trade delays to 1. The backtester sets the entry array (Buy or Sell) at the signal bar, but for visual purposes, we would consider the _next bar_ to be the bar of entry. In this case, we cannot report the EntryPrice at the signal bar without looking into the future. We can, however, report it 1 bar later (as done in the Title, below) */ // Setting delays to 1 means trade "next bar at" . // Setting delays to 0 means trade "this bar at" // ### Choose desired entry/exit style here. switch( TradingMode ){ case 1: // "Next bar at Open" trading BuyDelay = 1; BuyPrice = Open ; // LE at Open price of next bar ShortDelay = 1; ShortPrice = Open ; // SE at Open price of next bar SellDelay = 1; SellPrice = Open ; // LX at Open price of next bar CoverDelay = 1; CoverPrice = Open ; // SX at Open price of next bar break; case 2: // "This bar at Close" trading BuyDelay = 0; BuyPrice = Close ; // LE at Close price of signal bar ShortDelay = 0; ShortPrice = Close ; // SE at Close price of signal bar SellDelay = 0; SellPrice = Close ; // LX at Close price of signal bar CoverDelay = 0; CoverPrice = Close ; // SX at Close price of signal bar break; case 3: // Mixed mode trading, enter "Next bar at Open", exit "This bar at Close" BuyDelay = 1; BuyPrice = Open ; // LE at Open price of next bar ShortDelay = 1; ShortPrice = Open ; // SE at Open price of next bar SellDelay = 0; SellPrice = Close ; // LX at Close price of signal bar CoverDelay = 0; CoverPrice = Close ; // SX at Close price of signal bar break; /* case 4: // bad results for reversal trades! - this is a bogus case! // Mixed mode trading, , enter "This bar at Close", exit "Next bar at Open" BuyDelay = 0; BuyPrice = Close ; // LE at Close price of signal bar ShortDelay = 0; ShortPrice = Close ; // SE at Close price of signal bar SellDelay = 1; SellPrice = Open ; // LX at Open price of next bar CoverDelay = 1; CoverPrice = Open ; // SX at Open price of next bar break; */ } SetTradeDelays( BuyDelay, SellDelay, ShortDelay, CoverDelay ) ; Short = Cover = 0 ; // zero these here, they will be calculated below // ***** Code for technical analysis calculation(s). // ### Add all desired TA calcs here. theLRS = LinRegSlope(Close, LRS_Base_Period) ; SmoothedLRS = MA(theLRS, LRS_Smooth_Period) ; // Re-Scale the TA plots (i.e. for FX) when there is a ScaleFactor other than 1 if (LRS_ScaleFactor != 1){ theLRS = theLRS * LRS_ScaleFactor ; SmoothedLRS = SmoothedLRS * LRS_ScaleFactor ; } // Choice of variations in the root signal calculation // ### Add new signal definition choices as desired LRS_IsLow = LRS_IsHigh = 0 ; // Buy weakness, sell strength - trade each area as it is entered if (SignalType == 1){ LRS_IsLow = (SmoothedLRS <= LRS_LowLvl) AND (Ref(SmoothedLRS, -1) > LRS_LowLvl) ; // weakness, touch/downcross of low threshold LRS_IsHigh = (SmoothedLRS >= LRS_HighLvl) AND (Ref(SmoothedLRS, -1) < LRS_HighLvl) ; // strength, touch/upcross of high threshold } // Buy weakness, sell strength - trade each area as it is exited else if (SignalType == 2){ LRS_IsLow = (SmoothedLRS >= LRS_LowLvl) AND (Ref(SmoothedLRS, -1) < LRS_LowLvl) ; // rebound from weakness, touch/upcross of low threshold LRS_IsHigh = (SmoothedLRS <= LRS_HighLvl) AND (Ref(SmoothedLRS, -1) > LRS_HighLvl) ; // breakdown from strength, touch/downcross of high threshold } // Output calculation values to Interpretation window. Put spaces after each value. printf( "LRS: " + WriteVal(theLRS, 1.2) + " " ) ; printf( "SmoothedLRS: " + WriteVal(SmoothedLRS, 1.2) + " " ) ; printf( "\n") ; // ***** Code for trading long-only, short-only, or in both directions // Setup to trade long only, short only, or in both directions. // This block predicated on working with only 2 (rather than 4) basic signals. // ### Make sure to always assign Buy, Sell, Short, and Cover to prevent undefined errors later. if (LongShortBoth == 1){ Sell = Short = Cover = 0 ; if (InvertSignals){ Buy = LRS_IsHigh; // Sell = LRS_IsLow; } else { Buy = LRS_IsLow; // Sell = LRS_IsHigh; } } else if (LongShortBoth == 2){ Buy = Sell = Short = 0 ; if (InvertSignals){ Short = LRS_IsLow; // Cover = LRS_IsHigh; } else { Short = LRS_IsHigh; // Cover = LRS_IsLow; } } else if (LongShortBoth == 3){ // Stop-and-reverse setup - appropriate when there are only 2 underlying signals as here. // Note that for stop-and-reverse case, AB requires the exit signal along with the new entry signal. /* Buy = LRS_IsLow; Sell = LRS_IsHigh; Short = Sell; Cover = Buy; */ // Beware - incorrect! /* Buy = LRS_IsLow; Short = LRS_IsHigh ; Sell = Cover = 0 ; */ // Stop-and-reverse setup - appropriate when there are only 2 underlying signals as here. // Note that for stop-and-reverse case, AB requires the exit signal along with the new entry signal. if (InvertSignals){ Buy = LRS_IsHigh; Sell = LRS_IsLow; Short = Sell; Cover = Buy; } else { Buy = LRS_IsLow; Sell = LRS_IsHigh; Short = Sell; Cover = Buy; } } // ===Dbg // printf( "a Buy: " + Buy + " Sell: " + Sell + " Short: " + Short + " Cover: " + Cover + "\n" ) ; // ***** Code for trading signals in the opposite direction // Optional inversion of trading signals if (InvertSignals){ printf( "Inverting Signals" + "\n" ) ; } // ***** Code for a choice of trade signal filters // ### Add add new/different filter types as desired // Choice of filters to apply. FilterType 0 means "no filter". if (FilterType == 1){ LongOK = ShortOK = 0 ; LongOK = Close > MA(Close, 200) ; ShortOK = Close < MA(Close, 200) ; } if (FilterType == 2){ LongOK = ShortOK = 0 ; LongOK = Close > MA(Close, 50) ; ShortOK = Close < MA(Close, 50) ; } // etc. for different filters, if desired if (FilterType != 0){ Buy = Buy AND LongOK ; Short = Short AND ShortOK ; } // ===Dbg // printf( "b Buy: " + Buy + " Sell: " + Sell + " Short: " + Short + " Cover: " + Cover + "\n" ) ; // ***** Code for limiting trading to an intraday time window (i.e. daytrading) // Intraday time restrictions when daytrading if (DaytradeOnly==1) { NoSecTime = .01 * TimeNum() ; // time to the minute only, dropping seconds printf( "Time: " + NumToStr( NoSecTime, 1.0) + "\n" ) ; Buy &= (NoSecTime >= NoEntriesBefore) AND (NoSecTime <= NoEntriesAfter) ; Sell &= (NoSecTime >= NoEntriesBefore) AND (NoSecTime <= NoEntriesAfter) ; Short &= (NoSecTime >= NoEntriesBefore) AND (NoSecTime <= NoEntriesAfter) ; Cover &= (NoSecTime >= NoEntriesBefore) AND (NoSecTime <= NoEntriesAfter) ; // EOD exits - force a sell or cover, which is ignored if there is no position on Sell |= (NoSecTime >= ExitAllTime) ; Cover |= (NoSecTime >= ExitAllTime) ; } // ***** Code for optimizable StopLoss and PftTgt if (UseStopsAndTgts){ /* ApplyStop( type, mode, amount, exitatstop, volatile = False, ReEntryDelay = 0 ) */ /* ----------------------- dynamic mode: */ ApplyStop(stopTypeLoss, IIf( StopLossPct > 0, stopModePercent, stopModeDisable), StopLossPct, 0, False, 0 ); ApplyStop(stopTypeProfit, IIf( PftTgtPct > 0, stopModePercent, stopModeDisable), PftTgtPct, 0, False, 0 ); ApplyStop(stopTypeTrailing, IIf( TrailStopPct > 0, stopModePercent, stopModeDisable), TrailStopPct, 0, False, 0 ); } // ***** Code for optimizable indicator-based exits // ### Set your exit reason text here. This is used for on-screen display. SellReason = "" ; CoverReason = "" ; if (UseIndLvlExits){ LvlSell = SmoothedLRS > LX_Above_Lvl ; LvlCover = SmoothedLRS < SX_Below_Lvl ; Sell |= ( LvlSell ) ; Cover |= ( LvlCover ) ; SellReason = SellReason + WriteIf( LvlSell, "LX_Above_Lvl - ", "" ) ; CoverReason = CoverReason + WriteIf( LvlCover, "SX_Below_Lvl - ", "" ) ; } // ***** Code for determining and displaying exit reasons // Calculate equity array, stops not written to buy/sell/short/cover arrays, use AA window date range. // P1_Equity = Equity(0, -1); // Calculate equity array, EVALUATE STOPS and write to buy/sell/short/cover arrays, use AA window date range. P1_Equity = Equity(1, -1); // generate exit reasons // Interpretation display of date range begin and end. // Done near the Equity() calculation, as this is the range over which equity is calculated. DateRangeBegin = Status("rangefromdate") ; DateRangeEnd = Status("rangetodate") ; printf( "DateRangeBegin: " + DateToStr( DateRangeBegin ) + "\n" + "DateRangeEnd: " + DateToStr( DateRangeEnd ) + "\n" ) ; // Capture stop reason information to strings. _N( SellReason = SellReason + WriteIf( Sell == 1, "Regular Exit\n", WriteIf( Sell == 2, "Max Loss\n", WriteIf( Sell == 3, "Profit Tgt\n", WriteIf( Sell == 4, "Trailing Stop\n", WriteIf( Sell == 5, "N-bar Stop\n", WriteIf( Sell == 6, "Ruin stop\n", "" ) ) ) ) ) ) ); _N( CoverReason = CoverReason + WriteIf( Cover == 1, "Regular Exit\n", WriteIf( Cover == 2, "Max Loss\n", WriteIf( Cover == 3, "Profit Tgt\n", WriteIf( Cover == 4, "Trailing Stop\n", WriteIf( Cover == 5, "N-bar Stop\n", WriteIf( Cover == 6, "Ruin stop\n", "" ) ) ) ) ) ) ); // _TRACE( "Sell: " + NumToStr( Sell ) ) ; // _TRACE( "Cover: " + NumToStr( Cover ) ) ; // Write to the Interpretation Window to explain the currently selected TradingMode switch( TradingMode ){ case 1: printf( "Mode 1: Next bar at Open trading (delay entries AND exits)" + "\n" ) ; break; case 2: printf( "Mode 2: This bar at Close trading (no delay of entries OR exits)" + "\n" ) ; break; case 3: printf( "Mode 3: Mixed mode trading, enter Next bar at Open, exit This bar at Close (delay entries, NOT exits)" + "\n" ) ; break; /* case 4: printf( "Mode 4: Mixed mode trading, enter This bar at Close, exit Next bar at Open (delay exits, not entries)" + "\n" ) ; break; */ } // ***** Code for histogram visualization of buy/sell/short/cover arrays. // Simple histogram visualization of buy/sell/short/cover arrays. // Different heights indicate different exit reasons, as per above. // Display range is confined to near bottom of pane. // ### Keep comments in sync with actual colors if you change them. if (ShowSignalsHistogram){ HistBaseVal = .5; HistMinVal = 0; HistMaxVal = 15; Plot( HistBaseVal + 1/Buy,"Buy",colorGreen,styleHistogram|styleOwnScale, HistMinVal, HistMaxVal); // Buy - Green Plot( HistBaseVal + 1/Sell,"Sell",colorRed,styleHistogram|styleOwnScale, HistMinVal, HistMaxVal); // Sell - Red Plot( HistBaseVal + 1/Short,"Short",colorOrange,styleHistogram|styleOwnScale, HistMinVal, HistMaxVal); // Short - Orange Plot( HistBaseVal + 1/Cover,"Cover",colorAqua,styleHistogram|styleOwnScale, HistMinVal, HistMaxVal); // Cover - Aqua } // ***** Code for passing NetPft to cooperating display indicator in another chart pane. if( Status("ActionEx") == actionIndicator ){ IE = GetOption("InitialEquity") ; // Returns single-security Equity line based on Buy/Sell/Short/Cover rules, // Buy/Sell/Short/CoverPrice arrays, all apply stops, AND all other backtester settings. // P1_Equity = Equity(0, -1); // just calculate the equity array, use AA window date range // Assign calculated equity to a static array so another pane can plot it if (EquitySend > 0) StaticVarSet("Equity_P" + EquitySend, P1_Equity ); NetPft = P1_Equity - IE; // local calculation of NetPft for use in Title } // end of: if( Status("ActionEx") == actionIndicator ) #1 // ***** Code for Displaying signals as an Exploration if( Status("ActionEx") == actionExplore ){ if (ExploreType == "Current"){ IsLastBar = DateTime() == LastValue(DateTime()) ; // filter on this to show current bar signals only in Exploration ExpDateCon = IsLastBar ; } else if (ExploreType == "Today"){ IsLastDate = DateNum() == LastValue(DateNum()) ; // filter on this to show last day's signals only in Exploration ExpDateCon = IsLastDate ; } else if (ExploreType == "Historical"){ ExpDateCon = 1 ; // allow historical signals in Exploration } if (LongShortBoth == 1){ Filter = ExpDateCon AND (Buy OR Sell) ; AddColumn( Buy, "Buy Next Bar", 1.0, colorDefault, IIf(Buy, colorGreen, colorDefault) ); AddColumn( Sell, "Sell Next Bar", 1.0, colorDefault, IIf(Sell, colorRed, colorDefault) ); } else if (LongShortBoth == 2){ Filter = ExpDateCon AND (Short OR Cover) ; AddColumn( Short, "Short Next Bar", 1.0, colorDefault, IIf(Short, colorRed, colorDefault) ); AddColumn( Cover, "Cover Next Bar", 1.0, colorDefault, IIf(Cover, colorGreen, colorDefault) ); } else if (LongShortBoth == 3){ Filter = ExpDateCon AND (Buy OR Short) ; AddColumn( Buy, "Buy Next Bar", 1.0, colorDefault, IIf(Buy, colorGreen, colorDefault) ); AddColumn( Short, "Short Next Bar", 1.0, colorDefault, IIf(Short, colorRed, colorDefault) ); } // ### Add exploration columns for all indicators AddColumn( theLRS, LRS_Name, 1.2, colorDefault, IIf(Buy, colorGreen, IIf(Short, colorRed, colorDefault)) ); AddColumn( SmoothedLRS, "Smoothed " + LRS_Name, 1.2, colorDefault, IIf(Buy, colorGreen, IIf(Short, colorRed, colorDefault)) ); } // end of: if( Status("ActionEx") == actionExplore ) // ***** Code for on-chart plotting of price, signal arrows, and trade duration/direction bar coloring // if( Status("ActionEx") == actionIndicator ){ if( Status("Action") == 1 ){ // INDICATOR // Enable/disable plotting of up/down arrows on the entry and exit signal bars. // This show location of signal generation, regardless of actual entry. if(PlotEntryArrows){ PlotShapes( shapeUpArrow * (Buy > 0), colorGreen,0, L, -20); // arrows at long entry bars PlotShapes( shapeDownArrow * (Short > 0), colorRed,0,H, -20) ; // arrows at short entry bars } if(PlotExitArrows){ // Don't plot exit arrows for reversal case - let the entry arrows indicate that instead PlotShapes( ( Buy == 0 ) * shapeUpArrow * (Cover > 0) , colorYellow,0, L, -20); // arrows at long exit bars PlotShapes( ( Short == 0 ) * shapeDownArrow * (Sell > 0), colorYellow,0,H, -20) ; // arrows at short exit bars } if ( (PlotRawPrice) ) { /* Color the price bars to indicate: Green - price performance after a Buy Signal (i.e. while long) Red - performance after a sell signal (i.e. while short) Yellow - signal bars */ // ### if you want to color the bars in a different way, this is where it is done switch( TradingMode ){ case 1: // "Next bar at Open" trading (delay entries and exits) AmLong = Flip( Ref(Buy, -BuyDelay), Ref(Sell, IIf(SellDelay == 0, -1, -SellDelay) ) OR Ref(Short, -ShortDelay) ) ; AmShort = Flip( Ref(Short, -ShortDelay), Ref(Cover, IIf(CoverDelay == 0, -1, -CoverDelay)) OR Ref(Buy, -BuyDelay) ) ; printf( "Next bar at Open trading (delay entries AND exits)" + "\n" ) ; break; case 2: // "This bar at Close" trading (no delay of entries or exits) AmLong = Flip( Ref(Buy, -1), Ref(Sell, -1) OR Ref(Short, -1) ) ; AmShort = Flip( Ref(Short, -1), Ref(Cover, -1) OR Ref(Buy, -1) ) ; break; case 3: // Mixed mode trading, enter "Next bar at Open", exit "This bar at Close" (delay entries, not exits) AmLong = Flip( Ref(Buy, -BuyDelay), Ref(Sell, -1) OR Ref(Short, -1) ) ; AmShort = Flip( Ref(Short, -ShortDelay), Ref(Cover, -1) OR Ref(Buy, -1) ) ; break; /* case 4: // Mixed mode trading, , enter "This bar at Close", exit "Next bar at Open" (delay exits, not entries) AmLong = Flip( Ref(Buy, -1), Ref(Sell, IIf(SellDelay == 0, -1, -SellDelay) ) OR Ref(Short, -1) ) ; AmShort = Flip( Ref(Short, -1), Ref(Cover, IIf(CoverDelay == 0, -1, -CoverDelay)) OR Ref(Buy, -1) ) ; break; */ } BarColors = IIf( AmShort, colorRed, IIf( AmLong, colorGreen, colorWhite ) ) ; if (PlotRawPrice) Plot( Close, " ", BarColors, PricePlotStyle ) ; } } SetChartOptions(0,chartShowArrows|chartShowDates); // ***** Code for creating and displaying informative title text // ### Configure your chart title as desired // Here is a fairly generic title, all in one line. // _N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) )); // Prepare a TitlePriceStr, in several steps if (ExtraDecimals){ // 5-decimal precision. Good for FX. Would make a cluttered display for stocks and futures. // _N() keeps this silent for later use. _N(TitlePriceStr = StrFormat( "O %.5f, H %.5f, L %.5f, C %.5f \nNetPft %.0f", O, H, L, C, NetPft )) ; } else { // 2-decimal precision. Good for stocks and futures. For FX, more decimals are typically needed // _N() keeps this silent for later use. _N(TitlePriceStr = StrFormat( "O %.2f, H %.2f, L %.2f, C %.2f \nNetPft %.0f", O, H, L, C, NetPft )) ; } // Configure a multi-line chart title, using the TitlePriceStr, and sometimes more. // Unknown - In Interpretation: why NetPft is 0, why BuySignal disappears ... // This is one giant line, down to the semicolon. Title = "\n" + Name() + " " + Date() + "\n" + TitlePriceStr + "\n" // Note that for for stop-and-reverse case, we don't want to display the exit part if the old-exit/new-entry pair. // This is accomplished by suppressing exit display when entry is also present. + WriteIf(Buy, "Buy Signal ", "") + WriteIf(Sell AND !Short, "Sell Signal - " + SellReason, "") + WriteIf(Short, "Short Signal ", "") + WriteIf(Cover AND !Buy, "Cover Signal - " + CoverReason, "") // These report the trade prices on the bar after the signal (where they are available). // This is appropriate when trading "open next bar" + WriteIf(Ref(Buy, -BuyDelay), StrFormat("Buy at %g", BuyPrice), "") + WriteIf(Ref(Short,-ShortDelay), StrFormat("Short at %g", ShortPrice), "") + WriteIf(Ref(Sell,-SellDelay) AND !Ref(Short,-ShortDelay), StrFormat(" Sell at %g", SellPrice), "") + WriteIf(Ref(Cover,-CoverDelay) AND !Ref(Buy,-BuyDelay), StrFormat(" Cover at %g", CoverPrice), "") + "\n" ; // Send raw Buy/Sell/Short/Cover to cooperating indicator for verification/debugging purposes. StaticVarSet(Formula_Name + "_Buy", Buy); StaticVarSet(Formula_Name + "_Sell", Sell); StaticVarSet(Formula_Name + "_Short", Short); StaticVarSet(Formula_Name + "_Cover", Cover); // ----- end of: P_LRS_06a.afl _SECTION_END(); // ***** Code for display of filters // ### Configure (or comment out) display of filters as desired. // The MA plots were added so as to visualize the filters. ShowMAs = ParamToggle( "ShowMAs", "No|Yes", 1 ); // default Yes, which displays the Moving Averages if (ShowMAs){ _SECTION_BEGIN("MA1"); P = ParamField("Price field", 3); Periods = Param("Periods", 200, 2, 200, 1, 0 ); Plot( MA( P, Periods ), _DEFAULT_NAME(), ParamColor( "Color", colorCycle ), ParamStyle("Style") ); _SECTION_END(); _SECTION_BEGIN("MA2"); P = ParamField("Price field", 3); Periods = Param("Periods", 50, 2, 50, 1, 0 ); Plot( MA( P, Periods ), _DEFAULT_NAME(), ParamColor( "Color", colorCycle ), ParamStyle("Style") ); _SECTION_END(); }