<jupyter_start><jupyter_text>Technical Analysis Template: sRoC + Stochastic Oscillator Buy and sell using oversold and overbought levels of the Stochastic oscillator according the trend. The trend indicator is the smooth Rate of Change with WMA as a smooth function.<jupyter_code>import qnt.graph as qngraph
import qnt.data as qndata
import qnt.stats as qnstats
import qnt.xr_talib as qnxrtalib

import xarray as xr
import pandas as pd
from qnt.stepper import test_strategy
#import qnt.forward_looking as qnfl

import xarray.ufuncs as xrf

import datetime as dt<jupyter_output><empty_output><jupyter_text>Data<jupyter_code>data = qndata.load_data(tail=dt.timedelta(days=5*365), dims=("time", "field", "asset"), forward_order=True)<jupyter_output>fetched chunk 1/6 1s
fetched chunk 2/6 2s
fetched chunk 3/6 4s
fetched chunk 4/6 5s
fetched chunk 5/6 6s
fetched chunk 6/6 7s
Data loaded 7s<jupyter_text>Calc output<jupyter_code>SROC_POSITIVE_TREND_LEVEL=0.05
SROC_CLOSE_LEVEL=-0.05

STOCH_OVERBOUGHT_LEVEL=92
STOCH_OVERSOLD_LEVEL=31

wma = qnxrtalib.WMA(data.sel(field='close'), 120)
sroc = qnxrtalib.ROCP(wma, 60)

stoch = qnxrtalib.STOCH(data, 8, 3, 3)
k = stoch.sel(field='slowk')
d = stoch.sel(field='slowd')

data_ext = xr.concat([wma, sroc, k, d], pd.Index(['wma', 'sroc', 'k', 'd'], name='field'))
data_ext = xr.concat([data, data_ext], 'field')

weights = data.isel(time=0, field=0)
weights[:] = 0


def step(data):
    latest = data.isel(time=-1)

    is_liquid = latest.sel(field="is_liquid")
    sroc = latest.sel(field='sroc')
    k = latest.sel(field='k')
    d = latest.sel(field='d')

    need_open = xrf.logical_and(
        sroc > SROC_POSITIVE_TREND_LEVEL, 
        xrf.logical_and(k < STOCH_OVERSOLD_LEVEL, d < STOCH_OVERSOLD_LEVEL)
    )
    need_close = xrf.logical_or(
        sroc < SROC_CLOSE_LEVEL, 
        xrf.logical_and(k > STOCH_OVERBOUGHT_LEVEL, d > STOCH_OVERBOUGHT_LEVEL)
    )

    global weights
    
    weights.loc[need_open] = 1
    weights.loc[need_close] = 0
    
    weights.loc[is_liquid == 0] = 0 # prevention of illiquid assets trading

    return (weights / weights.sum('asset')).fillna(0)


output = test_strategy(data_ext, step=step)<jupyter_output>Testing started...
Testing progress: 449/1257 5s
Testing progress: 894/1257 10s
Testing complete 14.093945503234863s<jupyter_text>Stats and plots<jupyter_code>stat = qnstats.calc_stat(data, output, max_periods=252 * 3)
display(stat.to_pandas().tail())
qngraph.make_plot_filled(
    stat.coords['time'].to_pandas(), 
    stat.loc[:, 'equity'].values,  
    color="blue", 
    name="PnL (Equity)", 
    type="log"
)
qngraph.make_plot_filled(
    stat.coords['time'].to_pandas(), 
    stat.loc[:, 'underwater'].values, 
    color="red", 
    name="Underwater Chart", 
    range_max= 0
)
SR_OFFSET = 252 * 3 + 120 + 60 + 8 * 3 * 3
qngraph.make_plot_filled(
    stat.coords['time'].to_pandas()[SR_OFFSET:], 
    stat.loc[:, 'sharpe_ratio'].values[SR_OFFSET:], 
    color="purple", 
    name="Rolling SR"
)
qngraph.make_plot_filled(
    stat.coords['time'].to_pandas(), 
    stat.loc[:, 'bias'].values, 
    color="gray", 
    name="Bias"
)<jupyter_output><empty_output><jupyter_text>Checks<jupyter_code>qnstats.print_correlation(output, data)<jupyter_output>WARNING! This strategy correlates with other strategies.
The number of systems with a larger Sharpe ratio and correlation larger than 0.8: 1
The max correlation value (with systems with a larger Sharpe ratio): 0.9055071260527578
Current sharpe ratio(3y): 0.592895288234106<jupyter_text>Save output<jupyter_code>qndata.write_output(output)<jupyter_output>write output: /root/fractions.nc.gz
{'fraction_non_alphanumeric': 0.12434662998624484, 'fraction_numerical': 0.03796423658872077, 'mean_word_length': 4.826923076923077, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '642028', 'license': 'MIT', 'n_tokens_mistral': 1530, 'n_tokens_neox': 1384, 'n_words': 291, 'path': 'ru/source/examples/examples_sRoc_Stochastic.ipynb', 'repo_name': 'Rponomarenko/documentation', 'size': '3635'}