Back to Community
Correct Stochastic Values

I'm struggling with stochastic values, the numbers don't match any charting sites out there that I can find.
Hope someone can shed some light on it.

%K values for AXP and two dates picked randomly:

               Quantopian    Yahoo        Google        TradingView    YCharts  
Date          (14,3,3)?      Slow(14,3)   Slow(14,3)    (14,3,3)       Slow(14,3)  
2014-4-4      33.04          21.28        21.99         21.99          21.99  
2014-4-24     76.28          39.86        43.36         43.37          43.36

6 responses

If optInSlowK_Period is 1 here it should be 3, however I think the results are the same.

Clone Algorithm
247
Loading...
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
stoch = ta.STOCH(
    optInFastK_Period = 14,
    optInSlowK_Period = 1,
    optInSlowD_Period = 3
)

def initialize(context):
    context.ticker = sid(679)    # AXP
    
def handle_data(context, data):
    stoch_data = stoch(data)
    stoch_vals = stoch_data[context.ticker]

    record(K = stoch_vals[0], D = stoch_vals[1])
    
There was a runtime error.

I'm not directly familiar with the stoch transformation in ta-lib, but according to the formula, it's based on the close and low prices. On Quantopian, we use a private data vendor to provide our historical prices. These prices are the aggregate of all intra-day stock activity across the major exchanges: NYSE, NASDAQ, AMEX and all Consolidated Tape Association (CTA) participants. So the close_price will be the price of stock at 4:00PM.

Conversely, Yahoo/Google and other sources use adjusted close prices in their graphs. Their close_price includes the trade activity in the dark pools and close auctions, which can fluctuate the price of the stock during non-market hours. This seems to be the culprit driving the differences that you're seeing.

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Two problems You need to set it to 14,3,3. 14,3,1, is ok, since you are not using the signal line, but 14,1,3 is, as they say in Monty Python, 'Right Out'.
Second, your constants are wrong. Here is my version.

Clone Algorithm
40
Loading...
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
getStoc = ta.STOCH(fastk_period=14,slowk_period=3,slowd_period=3)


#initialize the strategy 
def initialize(context):
    context.etf = sid(679)
    context.price={}

    
def handle_data(context, data):
    
    
    stoch_data = getStoc(data)
    stochVal = stoch_data[context.etf][0]
    stochsignal = stoch_data[context.etf][1]
    record(stoch=stochVal,signal=stochsignal,mid=50,topthreshold=80,bottomthreshold=20)
'''
stoch = ta.STOCH(
    optInFastK_Period = 0,
    optInSlowK_Period = 0,
    optInSlowD_Period = 0
)

def initialize(context):
    context.ticker = sid(679)    # AXP
    
def handle_data(context, data):
    stoch_data = stoch(data)
    stoch_vals = stoch_data[context.ticker]

    record(K = stoch_vals[0], D = stoch_vals[1])

'''
There was a runtime error.

The problem was in the switch names like optInFastK_Period.
Should have been fastk_period.
Then the values are nearly identical to Google and TradingView for example.

Hope someone can fix this evidently failed effort to compare/record talib.STOCH() vs ta.STOCH()

Clone Algorithm
23
Loading...
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
'''
Comparison of ta.STOCH() and talib.STOCH()

There is talk of deprecating ta (built-in) in favor of talib.
'''

import talib        # for talib.STOCH()

fast_k = 14
slow_k = 3
slow_d = 3

# Object for ta.STOCH() (built-in) stochastic values:
ta_getStoch = ta.STOCH(
    fastk_period = fast_k, 
    slowk_period = slow_k, 
    slowd_period = slow_d
)

# Function for talib.STOCH() stochastic values:
def stoch_talib(sid):
    ''' Help from https://www.quantopian.com/posts/sample-using-history-and-stochastics
    '''
    highs  = history(44, '1d', 'high')
    lows   = history(44, '1d', 'low')
    closes = history(44, '1d', 'close_price')
    
    stoch_data = talib.STOCH(
        highs[sid],
        lows[sid],
        closes[sid],
        fastk_period = fast_k,
        slowk_period = slow_k,
        slowd_period = slow_d,
        #slowk_matype = 0,
        #slowd_matype = 0
    )
    
    slowk = stoch_data[0][-1]
    return slowk
    
def initialize(context):
    context.ticker = [
        symbol('goog_l'),
        symbol('aapl'),
    ]        
    
def handle_data(context, data):
    for sec in data:
        
        # TA STOCH (built-in) 
        ta_stoch_data = ta_getStoch(data)
        ta_stoch_k    = ta_stoch_data[sec][0]
        if str(sec.symbol) == 'AAPL':
            record(ta_K = ta_stoch_k)
        
        # talib STOCH (from import talib)
        talib_stoch_k = stoch_talib(sec)
        if str(sec.symbol) == 'AAPL':
            record(talib_K = talib_stoch_k)
    
There was a runtime error.

talib.stoch vs ta.stoch (7/2014)

ta.STOCH() helps identify ideal buy/sell points along with other indicators in my algo.
With ta to-be-deprecated it makes sense to be prepared with an accurate talib replacement.
In the following, ta.STOCH() is pretty close to accurate (acceptable) and talib.STOCH() is better than above yet inaccurate.
This also has a manual stochastics calculation, pretty close to talib and therefore also inaccurate.

Clone Algorithm
23
Loading...
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
'''
Comparison of ta.STOCH() and talib.STOCH() (and also a manual calculation)

There is talk of deprecating ta (built-in) in favor of talib
so a talib route would be useful if accurate.
'''

import talib        # for talib.STOCH()
import numpy as np  # for talib.STOCH()

fast_k = 14
slow_k = 3
slow_d = 3

lookback = 18 # if set to fast_k, or 14, no results from stoch_talib()

def initialize(context):
    context.tickers = [
        symbol('aapl'),
        symbol('goog_l'),
    ]
    context.books = {}
    for t in context.tickers:    # for talib library
        context.books[t] = {
            'prices': [],
            'highs' : [],
            'lows'  : [],
        }
        
def handle_data(context, data):
    for sec in data:
        if str(sec.symbol) == 'AAPL':
            # TA STOCH (built-in) 
            ta_stoch_data = ta_getStoch(data)
            ta_stoch_k    = ta_stoch_data[sec][0]
            record(ta_K = ta_stoch_k)
        
            # talib STOCH (from import talib)
            talib_stoch_k = stoch_talib(context, sec, data[sec].price)
            record(talib_K = talib_stoch_k)
            
            # Manual stochastic
            manual_stoch_k = stoch_manual(context, sec, data[sec].price)
            record(manual_K = manual_stoch_k)
            
# Object for ta.STOCH() (built-in) stochastic values:
ta_getStoch = ta.STOCH(
    fastk_period = fast_k, 
    slowk_period = slow_k, 
    slowd_period = slow_d
)

# Function for talib.STOCH() stochastic values (not accurate):
def stoch_talib(context, sid, price):
    ''' see for example
    http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:stochastic_oscillator_fast_slow_and_full

    The library imported as talib requires not just a price list as input, 
    instead also a list of the highest highs and lowest lows as if it could not 
    figure those out by itself, unbelievable.
    That's highs/lows for the lookback period window, NOT highs/lows in terms of OHLC.
    This won't work:
    highs  = history(lookback, '1d', 'high')
    lows   = history(lookback, '1d', 'low')
    closes = history(lookback, '1d', 'close_price')
    
    '''
    # Keep a list of prices
    context.books[sid]['prices'].append(price)
    # Limit to lookback size, trailing end
    context.books[sid]['prices'] = context.books[sid]['prices'][-lookback:]

    # List of highs and lows
    prices_sorted = sorted(context.books[sid]['prices'])
    high = prices_sorted[-1]
    low  = prices_sorted[0]
    context.books[sid]['highs'].append(high)
    context.books[sid]['lows'].append(low)
    # Limit to lookback size, trailing end
    context.books[sid]['highs'] = context.books[sid]['highs'][-lookback:]
    context.books[sid]['lows']  = context.books[sid]['lows'][-lookback:]

    if len(context.books[sid]['highs']) < lookback:
        return 0
    else:
        stoch_data = talib.STOCH(
            np.array(context.books[sid]['highs']),
            np.array(context.books[sid]['lows']),
            np.array(context.books[sid]['prices']),
            fastk_period = fast_k,
            slowk_period = slow_k,
            slowd_period = slow_d,
            slowk_matype = 0,
            slowd_matype = 0
        )
    
        slowk = stoch_data[0][-1]
        print slowk
        return slowk
    
# Manual calculation (not accurate)    
def stoch_manual(context, sid, price):
    ''' 
    Calculate Stochastic
    Formula:
    %K = (Current Close - Lowest Low) / (Highest High - Lowest Low) * 100
    %D = 3-day SMA of %K (unused here)
    
    Lowest Low   = lowest low   for the lookback period
    Highest High = highest high for the lookback period
    %K is multiplied by 100 to move the decimal point two places
    Values are 0 to 100
    '''
    
    '''
    Some of this commented, already done in stoch_talib() ...

    # Keep a list of prices
    context.books[sid]['prices'].append(price)
    # Limit to lookback size, trailing end
    context.books[sid]['prices'] = context.books[sid]['prices'][-lookback:]

    # List of highs and lows
    prices_sorted = sorted(context.books[sid]['prices'][-fast_k:])
    high = prices_sorted[-1]
    low  = prices_sorted[0]
    context.books[sid]['highs'].append(high)
    context.books[sid]['lows'].append(low)
    '''
    
    # Limit to ***fast_k*** size, trailing end
    highs = context.books[sid]['highs'][-fast_k:]
    lows  = context.books[sid]['lows'][-fast_k:]

    highs_sorted = sorted(highs)
    lows_sorted  = sorted(lows)
    
    highest_high = highs_sorted[-1]
    lowest_low   = lows_sorted[0]
    
    if highest_high == lowest_low:   # All prices same, don't divide by zero.
        slowk = 100.0
    else:
        slowk = ( (price - lowest_low) / (highest_high - lowest_low) ) * 100

    return slowk
                
            
            
    
There was a runtime error.