What to return from prices_to_signals when we don't want to buy or sell?

From the documentation, 1=long, 0=cash, -1=short. In the code 1=BUY, -1=SELL and 0=SELL. Can I make my strategy, not take any action? What is the recommended way of doing this?

To take no action, the signal should be the same as the previous day:

2023-11-28 0 # in cash
2023-11-29 1 # buy
2023-11-30 1 # hold

I am using an intraday strategy, making trades every minute. Consider:

1=BUY, -1=SELL and 0=SELL

If I want to :

minute 1 -> buy, signal=1
minute 2 -> buy, signal=?

Instead of thinking of 1 and -1 as buy and sell, think of them as the desired position: 1 = long, -1 = short, 0 = cash. By convention, prices_to_signals typically just returns -1s, 1s, and 0s, and then signals_to_target_weights converts those signals into weights, where 1=100% long, 0.5 = 50% long, -0.5 = -50% short, etc. In a multi-asset strategy, you might size positions equally such that the weights sum to 1.

Let's say that you have a single-asset strategy and that in minute 1, your signal is 1 and your target weight is 1. You will go 100% long the security. In minute 2, if you want to stay 100% long, the signal and target weight should again be 1. If you want to buy more of the security and increase your position size, the target weight will need to be greater than 1.

This helps. I indeed have a single-asset strategy using FXEURUSD. Taking my example:

If I want to :

minute 1 -> buy, signal=1, weight=1
minute 2 -> buy, signal=1, weight=2 (this will increase my position size from 1 to 2 and not place an order of 2 more instead)
minute 3 -> hold, signal=1, weight=2 (does not do anything)
minute 4 -> sell, signal=1, weight=-2(sells all 2 positions)

For minute 4, if you want to close the position and go to cash, the weight should be 0, not -2. -2 means you want to be 200% short. The weights are the desired end results, the diff() of weights tells you what needs to happen to get to those weights.

Try making a Series of weights and taking a diff() in a notebook:

In [1]: import pandas as pd
In [2]: weights = pd.Series([1, 2, 2, 0]) # desired end result
In [3]: weights.diff() # how to get there

Also, you have signal=1 in each of your minutes, but normally signals and weights would have the same sign, though they may differ in magnitude.

Brian

In that case, why do we need signals at all and why would their values change anything? Looks like you expect the weight vector to hold all the information about the portfolio.

Separation of concerns is the main reason to treat signals and target weights as two separate steps. It's common in finance to first identify a portfolio of securities you want to hold, then to decide how to allocate your capital among them. In Moonshot, the convention is to produce a DataFrame of signals in prices_to_signals that indicate only the direction of the position: -1, 1, or 0. Then, using those signals, you define the weights in signals_to_target_weights (e.g. equal weights by dividing 1 by the daily count of signals). Could you do it differently? Sure. You could put all the logic for generating the weights in prices_to_signals then just return the signals DataFrame that's provided to signals_to_target_weights as the weights. Or you could do nothing in prices_to_signals and have all the logic in signals_to_target_weights. It's a matter of convention.