Binary Signal Efficiency: When Scalable Code Bites Back
How a 10% gross exposure bug taught me to rethink signal handling.
Hey friends,
Today I want to walk you through a problem I ran into while building out my trading infra. One of those annoying bugs that shows up when you’re trying to scale the code, to handle a lot of different things, from a centralized place.
I’ve been designing my system to scale across asset classes, exchanges, different strategy types, etc etc. The goal is always: build once, use everywhere.
But then I ran into something.
By the way, if you’ve been reading my blog as of late, this all “new infrastructure” talk is starting to produce interesting results, although still a small sample. Crypto has been doing really poorly, and our new portfolio of strategies, has been handling it quite well. I’ll write a performance update, soon…
When testing a binary signal (which, in most cases, is not the most efficient way to look at a signal), I noticed we were creating a very low gross exposure profile for the strategy.
Mean of 10.9%. Median of 5%. That’s... not great.
What’s Actually Happening Here?
Let me explain how a binary signal works in my system, with a very simple example:
If close > xSignal, you get a long.
If close < xSignal, you get a short.
Simple enough.
The issue is that on a day to day basis, this doesn’t scale well with my overall infra.
Here’s why. Let’s say I don’t want to just measure my signal at entry or exit, but I want to measure each day against a pool of signals. Why? Because imagine you’re targeting a certain volatility AND you have a bunch of signals “feeding” into your overall weight on the market. You can periodically adjust your exposure based on that volatility target AND signal weight.
But that means periodic checks when you’re designing the system.
When I designed mine, I added a bit of something extra. Say you only allow X amount of positions in any given day, and the current signal is the weakest out of all available signals. What I do is remove that position from my open positions and allocate to the next one on the list.
# If not in signals, or if using continuous signals
# and not in signal list, set target to 0
if not asset_in_signals:
target_position_size = 0
would_flip = True
reason = "asset not in top signals"Makes sense right? Rank signals, keep the best ones, rotate out the weak ones.
Here’s where it breaks.
The Binary Signal Problem
A binary signal is a single event. The way I have my infra coded, binary signals are only accounted for at the entry/exit of their signal, not continuously. Why that design? Because if we fill the following dates forward with the binary signal, we might enter a new position when another position drops off our current open positions - but we didn’t get a binary signal for it on the current day.
Let me use a concrete example.
BTC gave a breakout signal on the 22nd of April 2025. That gives us a “1” signal, full allocation for that asset.
However, if this signal is now long for the following days until an exit, the code could open that position any time between that entry point and the exit point. Because now it’s always 1 going forward.
So the design to handle continuous adjustment of signals does not work well with a binary type event.
We need to re-think it.
Finding The Bug
The bug that was creating the 10% average gross exposure, is that a position exits just because it didn’t had a signal today. Remember how we check for positions on a day to day basis to scale well with continuous models?
Look at how XRP exits the position on the 6th of January 2026.
While at the same time, the signal strength on the individual asset, is actually 1, and never exited the position.
Obviously this is a design flaw that we need to fix. The first thing I did was pinpoint exactly why XRP exits on the 6th. The reason on the logs is that the asset is “not in top signals anymore.”
But why is it not in the top signals?
Because as mentioned above, being a binary signal, it only generates a long/short signal at the binary event. But the infra design choice requires it to be a “long_signal”, or “short_signal”, in order to be included in the valid signals list for that day:
if signal_calculation_method == "continuous":
valid_signal = (pd.notna(row['signal_strength']) and
row['signal_strength'] != 0 and
pd.notna(row['date']) and
row.get('annualized_volatility_20', 0) != 0)
else:
# For binary signals, check for any long or short signal being True
long_signal_cols = [col for col in row.index if col.startswith('long_signal_')]
short_signal_cols = [col for col in row.index if col.startswith('short_signal_')]
has_long_signal = any(row.get(col, False) for col in long_signal_cols)
has_short_signal = any(row.get(col, False) for col in short_signal_cols)
valid_signal = ((has_long_signal or has_short_signal) and
all(pd.notna(row.get(col)) for col in ['date']))
So the issue is that a long_signal and short_signal only occur at the binary event. That’s the crux of the matter.
Yes, we can’t just fill forward until there’s an exit, because my infra is more complex to handle a wide variety of signal types and that wouldn’t merge well.
So I need to figure out a way to ensure it’s scalable and handles these variations.
Breaking It Into First Principles
I always try to break things into first principles.
The first thing is that we want to ensure binary signals stay on for as long as it takes until they exit. So my first idea: if the model is based on a target volatility BUT with no rebalances, should we just skip checking if the position is still in the top signals?
As I considered it, it actually makes sense. If we don’t intend on rebalancing or making any adjustment before the exit signal, we don’t have to check if there’s a better signal on a day to day basis.
However, it might matter if we have a bunch of binary signals informing the exposure and suddenly one is better than the other. Then I might want to issue a rebalance.
But no, actually. If we think about it practically, let’s say we have a new signal that’s now higher ranked than one we already had. If we exit, we basically have to re-issue the entire exposure for this new signal at a price that is not the binary event price (entry/exit). That might not be the behavior we want.
So let’s start by testing this first idea.
What I did is add the option to require a material change on the signal to issue new exposure. For example:
If the signal inverts, we target a position of 0 (signal flipped)
If the signal directionality is the same but increases, we issue a new position based on current volatility and signal strength
elif volatility_targeting and rebalance_threshold == 1:
# When rebalance threshold is 1 (no rebalancing), maintain current position
# But exit if signal inverts (changes sign)
if (previous_signal_strength > 0 and current_signal_strength <= 0) or \
(previous_signal_strength < 0 and current_signal_strength >= 0):
target_position_size = 0
would_flip = True
reason = "signal inversion with no rebalancing"
# If signal increases in direction, calculate new position
elif (signal_type == 'long' and current_signal_strength > previous_signal_strength) or \
(signal_type == 'short' and current_signal_strength < previous_signal_strength):
target_position_size = (target_volatility / max_signals_for_day) / current_volatility * total_equity * current_signal_strength
target_position_size = min(target_position_size, total_equity * max_position_size_pct)
else:
target_position_size = current_position_value
This ensures the position only gets removed when there’s an actual exit signal. And then at the end of the day, the code goes back to all available signals and adds another signal that might be available.
The Result
What happens practically?
Our gross exposure goes up to 50% from the initial 10% we had.
Now, is a gross exposure of 50% the best allocation of capital?
Well, we’ll look into that in a later article.
I hope you’ve enjoyed today’s more “exploratory” post!
Disclaimer: The content and information provided by the Trading Research Hub, including all other materials, are for educational and informational purposes only and should not be considered financial advice or a recommendation to buy or sell any type of security or investment. Always conduct your own research and consult with a licensed financial professional before making any investment decisions. Trading and investing can involve significant risk of loss, and you should understand these risks before making any financial decisions.








