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% (39443 of 39443) |##################| Elapsed Time: 0:00:00 Time:  0:00:00
100% (14717216 of 14717216) |############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 1/6 1s
100% (14720244 of 14720244) |############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 2/6 2s
100% (14717184 of 14717184) |############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 3/6 3s
100% (14717100 of 14717100) |############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 4/6 4s
100% (14717100 of 14717100) |############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 5/6 5s
100% (13667388 of 13667388) |############| Elapsed Time: 0:00:00 Time:  0:00:00
fetched chunk 6/6 6s
Data loaded 7s
100% (104184 of 104184) |################| 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-04-18 9.432501 -0.004946 0.158673 -0.048533 -0.518614 0.778238 0.123485 1.0 246.0 0.112582 9.710233
2024-04-19 9.369116 -0.006720 0.158665 -0.054927 -0.518614 0.775630 0.123066 1.0 246.0 0.112561 9.710233
2024-04-22 9.444973 0.008097 0.158658 -0.047275 -0.518614 0.778456 0.123509 1.0 246.0 0.112541 9.710233
2024-04-23 9.543238 0.010404 0.158658 -0.037363 -0.518614 0.782089 0.124085 1.0 246.0 0.112534 9.710969
2024-04-24 9.580230 0.003876 0.158644 -0.033631 -0.518614 0.783411 0.124283 1.0 246.0 0.112526 9.720517
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-04-24
Sharpe Ratio = 0.757662264253069
ERROR! The Sharpe Ratio is too low. 0.757662264253069 < 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)