strategy

Q18 Technical Analysis using Index Data

This strategy uses the SP500 index data and technical indicators to trade NASDAQ stocks.

You can clone and edit this example there (tab Examples).


Predicting stocks from the NASDAQ 100 index using the SPX index and technical analysis indicators

In [1]:
from IPython.display import display
import xarray as xr
import qnt.data as qndata
import qnt.output as qnout
import qnt.ta as qnta
import qnt.stats as qns


def get_SPX(market_data):
    index_name = 'SPX'
    index_data = qndata.index.load_data(assets=[index_name], min_date='2005-01-01', forward_order=True)
    spx_data = index_data.sel(asset=index_name)
    spx_data = xr.align(spx_data, market_data.isel(field=0), join='right')[0]
    return spx_data


def get_strategy_1(data, spx, params):
    def get_trix(prices, index, periods):
        result = prices.copy(True)
        t = qnta.trix(index, periods)
        for a in prices.asset.values:
            result.loc[{"asset": a}] = t
        return result

    trix = get_trix(data.sel(field='close'), spx, 40)

    strategy_1 = trix.shift(time=params[0]) < trix.shift(time=params[1])
    strategy_2 = trix.shift(time=params[2]) > trix.shift(time=params[3])

    weights = strategy_1 * strategy_2 * data.sel(field="is_liquid")
    return weights.fillna(0)


def get_strategy_2(data, spx, params):
    def get_rsi(prices, index, periods):
        result = prices.copy(True)
        r = qnta.rsi(index, periods)
        for a in prices.asset.values:
            result.loc[{"asset": a}] = r
        return result

    rsi = get_rsi(data.sel(field='close'), spx, 40)

    strategy_1 = rsi.shift(time=params[0]) < rsi.shift(time=params[1])
    strategy_2 = rsi.shift(time=params[2]) > rsi.shift(time=params[3])

    weights = strategy_1 * strategy_2 * data.sel(field="is_liquid")
    return weights.fillna(0)


def get_strategy_3(data, spx, params):
    def get_roc(prices, index, periods):
        result = prices.copy(True)
        r = qnta.roc(index, periods)
        for a in prices.asset.values:
            result.loc[{"asset": a}] = r
        return result

    roc = get_roc(data.sel(field='close'), spx, 15)

    strategy_1 = roc.shift(time=params[0]) < roc.shift(time=params[1])
    strategy_2 = roc.shift(time=params[2]) > roc.shift(time=params[3])

    weights = strategy_1 * strategy_2 * data.sel(field="is_liquid")
    return weights.fillna(0)


data = qndata.stocks.load_ndx_data(min_date="2005-01-01")
spx = get_SPX(data)

weights_1_1 = get_strategy_1(data, spx, [142, 54, 132, 63])  # 1.0330127484868614 Sharpe Ratio
weights_1_2 = get_strategy_1(data, spx, [166, 75, 46, 24])  # 0.9591131817092265 Sharpe Ratio
weights_2 = get_strategy_2(data, spx, [159, 78, 77, 167])  # 0.8568070000760702 Sharpe Ratio
weights_3 = get_strategy_3(data, spx, [10, 27, 29, 41])  # 0.835419 Sharpe Ratio

weights_all = weights_1_1 + weights_1_2 + weights_2 + weights_3
weights = qnout.clean(output=weights_all, data=data, kind="stocks_nasdaq100")


def print_statistic(data, weights_all):
    import plotly.graph_objs as go
    import qnt.stats as qnstats

    stats = qnstats.calc_stat(data, weights_all)
    display(stats.to_pandas().tail(5))

    equity_curve = stats.loc[:, "equity"]
    fig = go.Figure(data=[
        go.Scatter(
            x=equity_curve.time.to_pandas(),
            y=equity_curve,
            hovertext="Equity curve",
        )
    ])
    fig.update_yaxes(fixedrange=False)
    fig.show()


print_statistic(data, weights)
100% (367973 of 367973) |################| Elapsed Time: 0:00:00 Time:  0:00:00
100% (40502 of 40502) |##################| Elapsed Time: 0:00:00 Time:  0:00:00
100% (14648104 of 14648104) |############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 1/7 1s
100% (14648104 of 14648104) |############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 2/7 2s
100% (14648100 of 14648100) |############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 3/7 3s
100% (14648072 of 14648072) |############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 4/7 5s
100% (14647992 of 14647992) |############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 5/7 6s
100% (14647992 of 14647992) |############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 6/7 8s
100% (3588140 of 3588140) |##############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 7/7 8s
Data loaded 9s
100% (105324 of 105324) |################| Elapsed Time: 0:00:00 Time:  0:00:00
Output cleaning...
fix uniq
ffill if the current price is None...
Check liquidity...
Ok.
Check missed dates...
Ok.
Normalization...
Output cleaning is complete.
field equity relative_return volatility underwater max_drawdown sharpe_ratio mean_return bias instruments avg_turnover avg_holding_time
time
2024-09-04 9.688314 0.0 0.158096 -0.053595 -0.52086 0.775050 0.122532 1.0 250.0 0.111670 9.816776
2024-09-05 9.688314 0.0 0.158080 -0.053595 -0.52086 0.774962 0.122506 1.0 250.0 0.111647 9.816776
2024-09-06 9.688314 0.0 0.158064 -0.053595 -0.52086 0.774874 0.122480 1.0 250.0 0.111624 9.816776
2024-09-09 9.688314 0.0 0.158048 -0.053595 -0.52086 0.774787 0.122454 1.0 250.0 0.111602 9.816776
2024-09-10 9.688314 0.0 0.158032 -0.053595 -0.52086 0.774699 0.122428 1.0 250.0 0.111579 9.815815
In [2]:
qnout.check(weights, data, "stocks_nasdaq100")
qnout.write(weights)
Check liquidity...
Ok.
Check missed dates...
Ok.
Check the sharpe ratio...
Period: 2006-01-01 - 2024-09-10
Sharpe Ratio = 0.7490184873305229
ERROR! The Sharpe Ratio is too low. 0.7490184873305229 < 1
Improve the strategy and make sure that the in-sample Sharpe Ratio more than 1.
Check correlation.
WARNING! Can't calculate correlation.
Correlation check failed.
Write output: /root/fractions.nc.gz

Example of a strategy using technical analysis indicators

The example of a strategy with a sharpe ratio of 0.9615 trading 215 financial instruments

The strategy use sma, ema, adl (Advance–Decline line)

from IPython.display import display
import xarray as xr
import qnt.data as qndata
import qnt.output as qnout
import qnt.ta as qnta
import qnt.stats as qns

data = qndata.stocks.load_ndx_data(min_date="2005-01-01")


def get_strategy_1(data, params):
    buy = 1
    not_trade = 0
    close = data.sel(field="close")

    strategy_1 = xr.where(qnta.sma(close, params[1]) > qnta.sma(close, params[0]), buy, not_trade)
    strategy_2 = xr.where(qnta.ema(close, params[2]) > qnta.ema(close, params[3]), buy, not_trade)

    weights = strategy_1 * strategy_2 * data.sel(field="is_liquid")
    weights = weights / 100.0
    return weights.fillna(0)


def get_strategy_2(data, params):
    buy = 1
    not_trade = 0
    close = data.sel(field="close") * data.sel(field="is_liquid")

    adl = qnta.ad_line(close) * 1.0
    adl_dif = adl.shift(time=params[0]) - adl.shift(time=params[1])
    positive_trend = adl_dif > 0
    strategy_1 = xr.where(positive_trend, buy, not_trade)

    weights = strategy_1 * data.sel(field="is_liquid")
    return weights.fillna(0)


weights_1 = get_strategy_1(data, [25, 40, 12, 132])  # 0.6108887689714039 Sharpe Ratio
weights_2 = get_strategy_2(data, [34, 183])  # 0.6012686822757577

weights_all = 2 * weights_1 * weights_2 - weights_1
weights = qnout.clean(output=weights_all, data=data, kind="stocks_nasdaq100")  # 0.9615

# qnout.check(weights, data, "stocks_nasdaq100")
qnout.write(weights)