- ago
Hello,
I have a few questions on Building Block Systems and automatic trading.
Let's assume I have built a simple system like the following:

... and made backtest with the following settings:


With the 20% of equity I like to restrict the number of positions to about 5 symbols at a time.

With this I get good results in the backtest and I would like to trade it per auto-trade with an IB Papertrade-Account.

First Issue is: the system generates 500 Signals. But through the position size the backtest chooses somehow only a subset of those signals to actually buy symbols.
Even though I have configured a weight, it doesn't seem like the trades are executed according to their weight.

Question 1: Why is the signal with the heighest weight not executed as a trade (even though the limit of the order was reached)?

Question 2: What is the mechanism that chooses a small subset of the 500 signals.

Question 3: What do I need to change in the system, that the auto-trade system behaves similar to the backtest-system?

Thanks & best regards
0
377
Solved
18 Replies

Reply

Bookmark

Sort
Cone8
 ( 24.61% )
- ago
#1
Q1, Q2 - If you really want 500 candidates, then Weight is irrelevant for live trading because the the trades that hit their limit first are the ones that will fill those 5 positions first.

If you want to limit the candidates by weight, then you need to select a number of "Max Entry Signals". For example, say you only want the top 25 limit signals. In this case, you'll get the top 25 by weight and the backtest will discard the other 475 signals... and it will affect your results by a lot.

Q3 - As you've selected, if you really have the 10 minute granular data (1 minute granular would be far more accurate) for all the stocks, then trading should be reasonably close to the backtest.

The problem is that you will not have that data for the symbols that have been delisted. Consequently, a granular test will favor symbols with intraday data, such that delisted symbols will be "unfavored" (which isn't realistic) when buying power is limited.
0
- ago
#2
Thanks a lot for your answer. I have a few follow-up questions:

QUOTE:
... and it will affect your results by a lot.


Q4: Do you mean it will affect the results by a lot, because with only 25 Limit Order, there is a high chance that only a small part of it reaches the limit and therefore the overall exposure is much lower? Or because of what do you see the big effect?

Q5: Assumed I use the same system, just that in the strategy settings I don't use the granular Limit/Stop processing.


When I do the backtest, I can see, that almost every day 5 symbols were bought and the system has an exposure of almost 98%.

How does the backtest choose, which symbols get traded? The weight does not seem to play a role and the timing, when which symbol reaches first the limit price also doesn't play a role, as the granular processing is deactivated. What mechanism is used here instead? (I'm asking because I get very good result and I wonder how I could resemble the backtest in "real-life")

0
Glitch8
 ( 10.13% )
- ago
#3
the ones that get filled are the ones that hit the limit price. If there are more than 5 of those, then the Weight will come into play.

If you want to restrict things to only the Top-5 Weight symbols having a chance to place the order, then select Max Entry Signals to 5.
0
Cone8
 ( 24.61% )
- ago
#4
Here are the key concepts - it's important to understand each one.

1. With 500 symbols, you're almost 100% sure to get 5 trades that drop 1% from the previous close every day.

2. The only "realistic" Weight for determining the order that Limit orders would have been filled is TimeOfDay, which is what granular processing gives you.

3. Using your 5-symbol, 20% sizing scenario...

Granular Processing OFF; Weight NOT ASSIGNED
If more than 5 symbols (say 50) hit their limit price during the day, the backtest will pick 5 of the 50 symbols randomly.

Granular Processing OFF; Weight ASSIGNED
If more than 5 symbols (say 50) hit their limit price during the day, the backtest will pick 5 of the 50 symbols by Weight - in your example, the ones with the Lowest ROC. This is HIGHLY UNREALISTIC. (Using Weight in this manner is only realistic with Market orders because you can choose which orders you place in the Market by Weight.)

Granular Processing ON; Weight NOT ASSIGNED
If more than 5 symbols (say 50) hit their limit price during the day, the backtest will pick 5 of the 50 symbols by the earliest TimeOfDay that the trade would have filled on the intraday bar. If more than 5 filled (say 20) on the same earliest intraday bar, then the 5 of the 20 are chosen randomly.

Granular Processing ON; Weight ASSIGNED
If more than 5 symbols (say 50) hit their limit price during the day, the backtest will pick 5 of the 50 symbols by the earliest TimeOfDay that the trade would have filled on the intraday bar. However, if more than 5 filled (say 20) on the same earliest intraday bar, then the 5 of those 20 are picked by Weight.

Exception Scenario: applies to all of the above
If a Limit or Stop order is priced such that it will execute at the opening price of the bar, it will be assigned a "very high weight" such that it is processed in a backtest before other signals.

4. If you do as Glitch says, you'll have only 5 entry orders per day - only 5 trade candidates per day, ignoring the other 495. Whereas you're nearly sure to get 5 fills per day with 500 candidates, it's highly unlikely to get 5 fills each day if you choose "the 5" by any means - unless you have a crystal ball or purposely "peek" ahead with Strategy code.
1
Best Answer
- ago
#5
Hello Glitch and Cone,
thanks a lot for your answers. In the first step, I try to reproduce your described behavior for the case "Granular Processing OFF; Weight ASSIGNED".

However, I cannot completely reproduce your described behavior. I have tested like this.

Design Surface as before:


Backtest from 2023/10/01 until 2023/11/29:


These are the positions:


These are the signals (sorted by weight, highlighted are the symbols which met their price limit the next day [2023/11/30]):

PAYC (L 177.90)
APA (L 35.56)
ILMN (L 99.23)
STE (L 195.47)
CTVA (L 45.02)
So, these signals I would expect to be bought next day.


Backtest from 2023/10/01 until 2023/11/30 (same strategy settings, just the "to"-date one day later):

These are the positions (highlighted are the symbols actually bought by the backtest):

Only PAYC and APA matched my expectation. Why the other symbols were bought, I have no idea.

Can you please help me to understand the behavior?

Thanks in advance & best regards


0
Cone8
 ( 24.61% )
- ago
#6
You specified "Lowest Weight" in your rules.
Either look at the bottom of your Signals list to match the results you have, or change it to "Weight: Highest" and then check what you expected.
0
Glitch8
 ( 10.13% )
- ago
#7
Weight is always highest value first. Specifying Lowest ROC in the Rule doesn’t change that. All it does is multiple the indicator value by -1 when generating the Weight.

Do you have Limit Order Slippage turned on by any chance? I’ll recreate your setup tomorrow and see what I can determine.
0
Glitch8
 ( 10.13% )
- ago
#8
Anyway, I had a few minutes, and was able to determine the reason. Consider one of your signals, AMZN Buy 31 at Limit 146.32.

The following day, AMZN opened BELOW the limit price, at 144.77.

So naturally the backtester processed that fill, because that is what would have happened in live trading, regardless of Weight.

So WL8 is giving you a realistic simulation of the actual trading experience here.

If you want to LIMIT the entries to ONLY the ones with the highest weight, you'll need to use Maximum Entry Signals. But this will of course lead to many missed opportunities.
1
Cone8
 ( 24.61% )
- ago
#9
Thanks Glitch. That scenario isn't always in the forefront of my feeble mind.

Added to Post #4: Exception Scenario
0
- ago
#10
Thanks again for your inputs. That means from the around 500 signals, there were only three signals which reached the limit already with the opening. These had highest priority. After that there came the signals which had the highest priority according to weight.

That means I cannot get similar results in reality, as I cannot submit 500 limit orders to my broker (and cancel 495 order as soon as 5 orders filled).
And even if I could place 500 Limit Orders, I could still not get the same results, as the signals which were selected by weight were chosen in "retrospect at the end of the day".

Can you confirm?

Would it be possible to convert this system into an intraday system to reach a similar behavior as the EOD backtest. Then the system could monitor the 500 signals and place the limit orders for the first (e.g. 5) signals which have reached their limit. It's a slightly different system then (without the weight factor) ... but my backtest results are impossible to reach because of the selection of the filled orders in retrospect.
0
Glitch8
 ( 10.13% )
- ago
#11
Yes that's right, this is why we encourage the use of Weight mainly for market orders.

The problem is you don't know beforehand which of the symbols will hit the limit. So I can't see a way to get those results in live trading short of using a crystal ball.

For Limit systems, using Weight in this way is more of a way to just get consistent results, but it's not something that can be achieved in live trading.
1
- ago
#12
Thanks again for your response.

Would it be possible to convert this system roughly into an intraday system. Then the system could monitor the 500 signals on a minute-base and place the limit orders for the first (e.g. 5) signals which have reached their limit.

Such a system should then return similar results in the backtest and in the live trading. What do you think? Would it only be possible with a C# strategy or also with the building block system? (especially the usage of another timescale (--> Daily) might be difficult, I guess?)
0
Glitch8
 ( 10.13% )
- ago
#13
We already have a built-in feature that does this, it's called Granular Processing.
0
- ago
#14
But this does only help for the backtesting. For live-trading / auto-trading I would have the problem, that the system wants to place 500 Limit-Orders.

My idea was to implement this system as an intraday-trading system. Then the prices of the 500 signals could get monitored in Wealthlab over the day, and every time the price limit of one of the 500 "hypothetical orders" is reached, Wealthlab could place the actual order at the broker. Does this make sense?
0
Glitch8
 ( 10.13% )
- ago
#15
For live trading we have the Quotes tool, you could send all your Limit orders to the Quotes tool and it can monitor the prices and submit the ones that come close to the target price.
0
- ago
#16
Oh, great, thanks for the hint. I will try it out.
0
ww58
- ago
#17
Let's take a well know "Knife Juggler" strategy. It shows a quite impressive performance in its default state limited to 10% of equity size and 1.0 margin, which equals to 10 positions a day. This won’t happen in real life with limit orders, and then we will get much worse statistics.

My idea is to make a similar strategy, but launched on a 1 minute timeframe, which will look at the number of already open positions and buy with the market order if the number is less than 10.

At first I wanted to do it using OpenPositionsAllSymbols, but this way it won’t be possible to limit it to 10 per day, only to 10 open ones. Therefore, the second option is to simply record the number of positions opened today in a file, increasing the counter and checking it.

And as I understand it, I first need to do this option with a counter on a current daily implementation and granular processing in order to get more realistic test results.

Will this achieve what I want and is there a more elegant way?
0
Cone8
 ( 24.61% )
- ago
#18
Since you'll be using market orders you can increment a counter, simple and elegant. Just make it a static variable (so every symbol's class will be changing the same counter) and reset it in Pre or PostExecute().

CODE:
public override void PreExecute(DateTime dt, List<BarHistory> participants) {          _PositionsOpenedToday = 0;      // reset each day          } static int _PositionsOpenedToday = 0;
1

Reply

Bookmark

Sort