The money management tool comes to the rescue when QuantShare language cannot be used to implement a trading strategy. There are many examples of strategies (we will detail them later) that cannot be implemented using QuantShare programming language and thus we need a more advanced language such as CSharp or VB.Net. Strategy Rules The strategy uses only the S&P 500 Index ETF (SPY). Make sure that you add the "SPY" ticker symbol (if it does not exist) and that you download historical EOD data for this ETF (Using the default downloader). - Buy SPY on Monday at open when the previous week return is positive. Buy only 50% of the current capital. - Scale-in SPY (Buy the 50% remaining capital) when we have already an open position for SPY and when the previous week return is positive. - Sell SPY on Monday at open when the previous week return is negative or equal to zero. First Steps - Select "Analysis" then "Simulator" to open the Simulator Manager. - Create on "New" to create a new trading system - In "Strategy" tab, set the number of positions to one - In "Symbols & Dates" tab, set "SPY" in the symbols selection control - Select "Money Management" tab - Click on "Add a new money management script" - Under the script tab, click on "Update Script" In the "Advanced Money Management" form, we can catch five events: - OnStartSimulation: This script is executed before the simulation starts. Example of usage: Initialize variables, create inputs, update strategy settings... - OnClosePostion: This event is called before creating a sell/cover order. It is called only when an order is created using the QuantShare language. Example of usage: Ignore an order, decrease the number of shares to sell... - OnNewPosition: This event is called before creating a buy/short order. It is called only when an order is created using the QuantShare language. Example of usage: Ignore an order, update the number of shares to buy... - OnEndPeriod: This event is called on each new bar. It is called once for all symbols (and not for every symbol). Example of usage: Enter new positions, close existing positions based on certain criteria, scale in/out existing positions, update portfolio settings... - OnEndSimulation: This script is executed after the simulation ends. Example of usage: Create time-series variables, create metrics... Buy/Scale-in on Monday Our strategy buy rules consist of entering a new position when previous week return is positive and then buying more shares when the next week return is also positive. Select the "OnEndPeriod" event and type the following formula: if(Divers.CurrentDate.DayOfWeek == DayOfWeek.Friday) { MMPosition position = Portfolio.GetPosition("SPY"); TimeSeries close = Data.GetPriceSeries("SPY", "close"); double perf = ((close[0] / close[5]) - 1) * 100; if(perf > 0) { if(position != null) { double nbShares = Portfolio.GetAvailableCash("long") / close[0]; if(nbShares > 0) { Functions.AddLongPosition("SPY", (int)nbShares, Orders.OpenMarketOrder()); } } else { double nbShares = Functions.GetNumberShares("SPY", true, Orders.OpenMarketOrder()); nbShares = nbShares / 2; Functions.AddLongPosition("SPY", (int)nbShares, Orders.OpenMarketOrder()); } } else { if(position != null) { position.ClosePosition(); } } } Explanation Line 1: This condition is used to check whether the current day of the week is Friday or not. We want to buy on Monday open, so we have to issue our order on Friday close. Line 3: "Portfolio.GetPosition" function gets the position object. This object contains information about the underlying position. Example: Maximum drawdown, entry date, entry price, rank (In case we have used a ranking system in the trading system)... The function returns "null" if the portfolio does not contain any open position for SPY. The position object will be used later. Line 4: We create a close time-series using the "Data.GetPriceSeries" function. The first parameter gets a ticker symbol and the second one gets a price field: "close", "open", "high", "low", "volume"... Line 5: We calculate the previous week return. close[0] <- Gets the current bar close price close[5] <- Gets the close price 5 bars ago Line 6: We check whether the previous return is bullish or bearish. If it is positive then we move to line 8; otherwise, we move to line 25. Buy Logic Line 8: Here, we verify whether our portfolio contains an open position for SPY or not. In the former case, a scale-in order is initiated and the latter case a new buy order is created. Line 10: We calculate the number of shares to scale-in by dividing the available cash by SPY close price. If this number if higher than zero then we enter a new order to buy shares for "SPY" using an Open Market order (Buy at open of tomorrow). (Scale-in because we have already an open position for "SPY"). The simulator or backtester will buy shares with all the available cash in our portfolio. Line 18: We landed here because there is no open position for "SPY" in our portfolio. Because we have to buy an amount that corresponds only to 50% of the available capital, we must calculate the number of shares that represents 50% of our capital. To do this, we simply calculate the number of shares that corresponds to 100% of the capital and then divide this number by 2. Line 20: We create an order to buy "nbShares" of "SPY" using an Open Market order. Sell Logic Line 25: We check whether the position exists or not. If it does not then we do nothing (Nothing to sell). If it does exist then we move to line 27. Line 27: We close the position using the "ClosePosition" method of the "MMPosition" class. This trading system serves as an example and it is not intended to be traded. Create an input field Why do we need an input field? Imagine we want to test the previous money management script using the SPY return of the last 10 bars or 20 bars instead of the last week. We can do this is by opening the script then updating line number 5. Another way to do this is by creating an input field and then updating "line 5" by replacing "5" with the input field variable. The input field is visible when you select a trading system (Simulator Manager) and you can directly update its value with one click. Another advantage is that you can optimize the value and backtest several versions of your trading system. How to create the input field: First, we have to initialize it in the "OnStartSimulation" event. Select this event then type the following formula: Functions.SetNumericInput("Bars", 5, "N-Bar Return"); In the "OnEndPeriod" event, update line 5 and set the following line: double perf = ((close[0] / close[(int)(double)Variables.GetVariable("Bars")]) - 1) * 100; The function "Variables.GetVariable" returns our input variable. It returns a variable of object type. We must first convert it to the original type, which is "double" (Input variables are of type double or string). After that, we convert this variable to "int". Why we should use the money management tool In this example, we could have implemented the first buy and sell logic using QuantShare language. An example of such formula would be: buy = (dayofweek() == 5) and perf(close, 5) > 0; sell = (dayofweek() == 5) and perf(close, 5) < 0; However, currently there is no way to create scale-in or scale-out orders using the QuantShare language. Here are some examples of strategies that require the money management tool: - Actions created based on portfolio data/metrics (Example: Current return, past 30-day return, current portfolio drawdown, portfolio's positions...) - Update the percent equity to invest and the maximum number of position of the portfolio (or a category) based on criteria - Update positions and orders size dynamically - Combine several strategies
|