I'm tying to replicate a feature from an interesting trading system I have found, but having a hard time getting it working (as mostly..).
Suppose the following simplified system, where I trade top 1 symbol only. This would trigger trades each time the ranking changes, with a short Ema like this quite frequently.
SetSimSetting(_NbPositions, 1);
System = Ema((Perf(close,1)*21,21)); // Factor 21 is to get kind of monthly return
Rang = comp(System,"rank");
buy = Rang <=1;
Now, to reduce the trading frequency I'd like to apply a "pitch" called "hysteresis" with a decay factor to the last bought symbol. This delays the next switch till the factor has decayed sufficiently, or new symbol is true "rising star".
In pseudo-code (does not work like this in simulator, sadly):
Decay_factor = 0.02 // Decays to 50% within 50 days
Hysteresis = 2% * Math.Pow(1-decay_factor,barssince(buy)); // Let the 2% or whatever "pitch" decay exponentially starting from last buy of the currently hold symbol)
System = Ema(Perf(close,1)*21,21))+ Hysteresis; // Hysteresis above zero for currently held symbol, zero for all other
Rang = comp(System,"rank");
buy = Rang <=1;
So, for the currently hold symbol we need to calculate the barssince(buy), then determine the Hysteresis factor and add this to formula considered in ranking...
For simplicity I'd like to avoid coding the whole system in AMM, but rather use a smart comp() or custom function in Simulator.
Question is whether anybody is using similar approach I could hook-in, or has a smart idea how to code in Simulator?
Btw, here what I was coding in AMM and a custom function:
But: 1) Too complicated and even I could live with this 2) not working :-)
AMM on Period end:
----------------------------------------------------------
// Get Positions
MMPosition[] positions = Portfolio.GetOpenPositions();
if(positions.Length==0) // if no positions, then hysterisis = 0
{
Global.SetVariable("Hyst_Sym", (string)"Cash"); // Position Symbol
Global.SetVariable("Hyst_Bars", (double)0); // Bars Since Entry
}
for(int i=0;i<positions.Length;i++)
{
MMPosition pos = positions[i];
Global.SetVariable("Hyst_Sym", (string)pos.Symbol); // Position Symbol
Global.SetVariable("Hyst_Bars", (double)pos.BarsSinceEntry);
}
Custom Function to be called from Simulator:
----------------------------------
string sym_in = (string)Sym[0]; // Input symbol held currently (e.g. SPY)
double hyst_in = (double)Hysterisis[0]; // Input Hyst in % (e.g.2)
double alpha = 1 / (double)Decay[0]; // Decay factor in days (e.g. 50)
double hyst_out = 0;
string sym = (string)Global.GetVariable("Hyst_Sym");
double bars = (double)Global.GetVariable("Hyst_Bars");
It must be implemented in the money management script.
The above script is not working because QS formula is parsed before the backtesting starts. So the custom function is executed before the AMM.
You must perform all the calculation within the AMM.
Thanks QS, but I still want to get this running in Simulator to keep things easy.
Here a new test, works but not debugged, for sharing and getting feedback only!
// System Rules--------------------------------------------------------------
Frequency = FirstTradingDOM();
System = Ema(ref(close,1)*21,21);
Rang = comp(System,"rank");
///// Hysteresis
buy_sim = Frequency and (Rang <=assets) and MarketSignal; // simulate buy signal w/o hysteresis
Hyst = 2 * Pow(1-0.02,barssince(buy_sim)); // Calculate Hysteresis since last simulated buy
Switch = ref(System,1) != ref(comp(System,"max"),1) ==1; //Check if we switch this period and new rank is 1
System = iff(Switch, System + Hyst, System); // if we switch, then add Hyst to this symbol
Rang = comp(System,"rank"); // Update rank with hysteresis
// buy-----------------------------------------------------------------------
buy = Frequency and (Rang <=assets);
// Sell ---------------------------------------------------------------------
sell = Frequency and (Rang >assets);
Will output and compare vectors to see if logic is right, but at first sight indeed trades go down and hitrate up..
Let us say that a buy occurred at bar n 1500.
At bar n 1550, the position is still in place and a new "buy_sim" signal for the same security occurs. That signal is simply ignored.
However, in the function above, the function "barssince(buy_sim)" will calculate the number of bars since the last signal (not the purchase bar).
In most cases, there is no way to get the buy price using QS language simply because the QS formula is exected to get signals and is executed before applying the backtesting logic.
Ok, took me the weekend but at least my ego is pleased after finishing my first AMM script. Results are soso and script is lousy, so I will not post it here but share with the interested. QS, thanks for challenging as always!
Trading financial instruments, including foreign exchange on margin, carries a high level of risk and is not suitable for all investors. The high degree of leverage can work against you as well as for you. Before deciding to invest in financial instruments or foreign exchange you should carefully consider your investment objectives, level of experience, and risk appetite. The possibility exists that you could sustain a loss of some or all of your initial investment and therefore you should not invest money that you cannot afford to lose. You should be aware of all the risks associated with trading and seek advice from an independent financial advisor if you have any doubts.