Back to Community
Welles Wilder's ADX - Average Directional Index (technical indicator implementation)

An oldie but a goodie, I thought I'd share my code for a popular technical indicator, the ADX.

Introduced by Welles Wilder in his 1978 book New Concepts in Technical Trading Systems, along with the Minus Directional Indicator and the Plus Directional Indicator, the ADX forms part of a family of technical indicators developed by Wilder to help classify trends and trend strength.

Find out a little more about ADX here and here.

I've followed Wilder and used a rolling window of 14 days for the calculation window, which is used in various parts to allow for the smoothing Wilder implements. Changing the variable '''context.window_length''' should allow you to change this if you wish.

Finally, at the end of the code I implement a very crude trading strategy based on the indicator - am sure you guys can do better and be more inventive with this.

Clone Algorithm
814
Loading...
Backtest from to with initial capital
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
# Backtest ID: 5112255fb50c2c08e7fbf7e9
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.
40 responses

I'm not familiar with how ADX is calculated but does line 97 and 98 need to have "context.window_length" instead of 14?

@James - yep, absolutely

I would like to code an ADX pattern that shows up on the weekly and/or the monthly charts. I have a few really terrific patterns that I would like to share how to implement and backtest. I am not overly technical, BUT I have done the research on the patterns and can explain them and share them in layman's terms. Is it possible to connect with an interested party who is interested in collaboration?

Hello Michael,

I would be interested. As a start I reproduced Tim's results using TA-Lib. There are differences in the timing of trades but the overall result is the same.

A data window of 28 days is the minimum required. Returns vary with the window length:

28 days = 170.8%  
29 days = 180.2%  
30 days = 193.1%  
31 days = 200.9%  

P.

Clone Algorithm
186
Loading...
Backtest from to with initial capital
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
# Backtest ID: 527f6a12c6c06c07daae1f07
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.

Hi Peter,

Pretty astounding returns. I have a few patterns that are specific ADX patterns. Perhaps we can discuss and develop and backtest our strategy on here? I love this site and would like to collaborate as I have been in the markets for 13 years and might be interested in even launching a fund or a prop firm. If it goes well, we could be a big success for this site! And they could be a big boon for us as well. My email is [email protected].

Thanks for these, after reading this book I have been trying to replicate this strategy as well but have very little programming experience. From my understanding of the text, the higher the ADX of any given security, the more profitable it is to trade this system. That being said, is there a way to limit the universe to whatever stocks have the highest ADX at any given point in time? In other words, instead of simply choosing one security (in this case sid(19920)) and limiting trades to when that security has an ADX higher than 20 or 25, could we add code that would loop through all stocks available, select whichever has the highest ADX and buy/short that stock (given that all the other conditions in the model are met)?

Hello Chris,

Please see attached. Note that there is no real position sizing or money management going on here. Also, it doesn't trade the highest ADX but just all ADX over a threshold.

P.

Clone Algorithm
186
Loading...
Backtest from to with initial capital
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
# Backtest ID: 5280fbd0fcdf2107985a65e4
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.

Peter,

I appreciate the quick response. If I'm interpreting your source code correctly, this would limit the universe to stocks in the top 0.5 percentile in terms of trade volume, and trade any stocks in that universe with and ADX above 20 or 25, right? I guess my question is whether we can further limit the universe to just the stock with the highest ADX? As I mentioned, I am just starting to experiment with coding, but might this be achieved by looping through all stocks in the universe you limited it to, creating a dict of each stock name and its respective ADX, then pulling the max of this dict to pass through the ADX and DI based trading logic?

Thanks again for your help!

Hello Chris,

Yes, you are correct on all points. The 0.5% universe is around 31 stocks but it is revised each quarter. I'll have a look at selecting the highest ADX with a view to having fewer, better trades.

P.

Hello Chris,

This version trades the securities with the top N ADX values.

P.

Clone Algorithm
139
Loading...
Backtest from to with initial capital
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
# Backtest ID: 528cb9c91f4fe2202b3b9f11
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.

Hi all,
Quick question. I'm new to python, so please excuse what I imagine is a stupid question.

If I'm trying to reference a changing value from one bar to the next, how would I code that?

For example, (context.mDI > context.mDI????) if I'm setting the condition so that the current mDI is greater that the mDI from the previous bar, what would it look like?

Thanks for humoring a newbie.

Best,

Justin Davis

Thanks Peter, this is extremely helpful. Sorry for being a pain, but I have a few more questions that I would really appreciate if you could answer. They are related to the code itself, so shouldn't require much effort on your part.

1) Related to the checks you added (lines 28-37). Maybe I'm interpreting the first (lines 28-30) incorrectly, but my interpretation is that it is checking whether the date/time of the last trade in the given security is less than (and therefore before) the current time. Assuming that there has been at least one trade in the given security at any point in the past, wouldn't this condition always be true? For example, if 10 shares of XYZ were purchased in 2005, even if XYZ was taken off the market in 2006, this condition would still evaluate to true wouldn't it?

As for the second and third checks that follow (lines 31-37), I'm not sure I see their relevancy. The second, as far as I can tell, just prints any open orders, but doesn't do anything with the printed list, correct? The third (lines 35-37) limits the universe of stocks to only those with a current price over $500? I must be interpreting that wrong, as I can't contemplate how this would benefit the strategy.

2) Could you please just briefly explain what the code on line 41 does (if not np.isnan(ADX))?

3) In regard to the dayCount variable, is this just so any stock positions in the portfolio are automatically sold off (or purchased to close a short position) every 30 days?

Thanks again for all of your help! I plan on adding a few other elements to this strategy that should help minimize downside risk, and would be happy to share when finished.

Hello Justin,

One way is to use a fixed-length queue. See: https://www.quantopian.com/posts/stock-price-30-days-ago

from collections import deque

# in initialize  
context.MDIvalues = deque(maxlen=2)  

# append to window  
context.MDIvalues.append(mDI)  
# access where index 0 is yesterday and index 1 is today  
if context.MDIvalues[1] > context.MDIvalues[0]  

P.

Hello Chris,

Thanks for taking the time to have a look. To try to answer:

1) 'if data[stock].datetime < get_datetime():' is checking if the price for a security is a 'new' price. Prices are timestamped and prices and their timestamps are carried forward so that the data/price object always has a entry for each security at each time interval. This is a bit of a grey area. Some algos I've written fail if this check is not made. Note that 'continue' means 'don't continue but instead go to the next iteration of the for loop'.

With 'if get_open_orders(stock):' please ignore the print statement which is leftover from debugging. What I'm trying to do here is very inelegant but I want to avoid trading a security while I still have an open position caused by a partial fill in the last trade of that security. I've had algos get into real problems where a long position is sold at time t, remains partially filled at t+1, and a short trade in the same security is entered also at t+1. [This is where I have a major conceptual problem with Quantopian which seems to be synchronous with minutely events whereas trading with Interactive Brokers via Trader Workstation or their FIX gateway would be asynchronous and would (mostly) avoid this issue. I wonder if this is because each algo running in Quantopian is single-threaded but, as I say, I have conceptual problems in this area.]

With 'if data[stock].close_price > 500.00:' I'm avoiding trading 'BRK 'A'' with a price per share sometimes around $170,000. Note that 'continue' means 'don't continue'.

2) I changed the algo after the recent security issue. When service was first resumed I had problems importing zipline in order to use the TA-Lib library so I switched to the 'supported' TA-Lib functions. For ADX based on 14 periods the first result is available at period 28 with the prior values all being NaNs i.e. Not A Number.

3) For some reason I thought the best results with ADX might come from holding positions for a few days but that is not what I found so maybe the algo is defective. The best results often came by generating a new portfolio every day or after a much larger number of days than I would have guessed i.e. 30 trading days (~ 6 weeks).

Please add some ideas. At the moment the algo does literally nothing with position sizing or handling margin. At times it goes so short that the $1 M starting cash becomes $4M.

P.

Peter - I appreciate the quick response. Thanks for your suggestion.
Best,
Justin

Can anyone take a look at this? I'm having some issues that I identified through comments. Any suggestions are appreciated.

implementation of Welles Wilder's ADX as given in spreadsheet form here

http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:average_directional_index_adx#calculation

from collections import deque

Put any initialization logic here. The context object will be passed to

the other methods in your algorithm.

def initialize(context):
#using the NASDAQ100 etf
context.ndx = sid(19920)
#container to count the number of event windows we have cycled through
context.ticks = 0
#Wilder uses a rolling window of 14 days for various smoothing within
#the indicator calculation
context.window_length = 14
#a collection of data containers that will be used during steps of the calculation
context.highs = deque([0] * 2, 2)
context.lows = deque([0] * 2, 2)
context.closes = deque([0] * 2, 2)
context.true_range_bucket = deque([0] * context.window_length, context.window_length)
context.pDM_bucket = deque([0] * context.window_length, context.window_length)
context.mDM_bucket = deque([0] * context.window_length, context.window_length)
context.dx_bucket = deque([0] * context.window_length, context.window_length)
#not sure why I had to define these here, but to print them later when debuggin
#I found that I had to declare them here
context.av_true_range = 0
context.av_pDM = 0
context.av_mDM = 0
context.di_diff = 0
context.di_sum = 0
context.dx = 0
context.adx = 0
context.pDI = 0
context.mDI = 0
context.mDIvalues = deque(maxlen=2)
context.pDIvalues = deque(maxlen=2)
context.adxvalues = deque(maxlen=2)

Having A problem here

context.mDIvalues.append(mDI)  
context.pDIvalues.append(pDI)  
context.adxvalues.append(adx)  

pass

Will be called on every trade event for the securities you specify.

def handle_data(context, data):
#iterate event window counter
context.ticks += 1
#pass high, low, close prices to our rolling containers
context.highs.appendleft(data[sid(19920)].high)
context.lows.appendleft(data[sid(19920)].low)
context.closes.appendleft(data[sid(19920)].close_price)

#ensure no calculation on first window  
if context.closes[0] == 0:  
    high_less_low = 0  
    high_less_prec_close = 0  
    low_less_prec_close = 0  
    high_less_prec_high = 0  
    prec_low_less_low = 0  
    pDM_one = 0  
    mDM_one = 0  
else:  
    high_less_low = context.highs[0]-context.lows[0]  
    high_less_prec_close = abs(context.highs[0]-context.closes[1])  
    low_less_prec_close = abs(context.lows[0]-context.closes[1])  
    high_less_prec_high = context.highs[0]-context.highs[1]  
    prec_low_less_low = context.lows[1]-context.lows[0]  


#calculate the Plus Directional Movement  
if high_less_prec_high > prec_low_less_low:  
    pDM_one = max(high_less_prec_high,0)  
else:  
    pDM_one = 0

#calculate the Minus Directional Movement  
if prec_low_less_low > high_less_prec_high:  
    mDM_one = max(prec_low_less_low,0)  
else:  
    mDM_one = 0  

#add the current pDM and mDM to the bucket to aid calculation of the first point in the  
#smoothed statistic  
context.pDM_bucket.appendleft(pDM_one)  
context.mDM_bucket.appendleft(mDM_one)  

#calculate the True Range and add to bucket  
true_range = max(high_less_low,high_less_prec_close,low_less_prec_close)  
context.true_range_bucket.appendleft(true_range)  

#once we have collected enough data to have populated the rolling windows adequately  
#we can start the meat of the calculation  
if context.ticks < (context.window_length + 1):  
    context.av_true_range = 1  
    context.av_pDM = 0  
    context.av_mDM = 0  
elif context.ticks == (context.window_length + 1):  
    context.av_true_range = sum(context.true_range_bucket)  
    context.av_pDM = sum(context.pDM_bucket)  
    context.av_mDM = sum(context.mDM_bucket)  
else:  
    context.av_true_range = context.av_true_range - (context.av_true_range/context.window_length) + true_range  
    context.av_pDM = context.av_pDM - (context.av_pDM/14) + pDM_one  
    context.av_mDM = context.av_mDM - (context.av_mDM/14) + mDM_one

if context.ticks > context.window_length:  
    context.pDI = 100 * context.av_pDM / context.av_true_range  
    context.mDI = 100 * context.av_mDM / context.av_true_range  
    context.di_diff = abs(context.pDI - context.mDI)  
    context.di_sum = context.pDI + context.mDI  
    context.dx = 100 * context.di_diff / context.di_sum  


#add to bucket to provide an average of the DX figures that will  
#act as a starting point for the rolling ADX calculation  
context.dx_bucket.appendleft(context.dx)

#the rolling ADX calculation  
if context.ticks == (context.window_length * 2):  
    context.adx = sum(context.dx_bucket) / context.window_length  
elif context.ticks > (context.window_length * 2):  
    context.adx = ((context.adx * (context.window_length - 1)) + context.dx) / context.window_length  

# Having TROUBLE with this Trading Logic
# access where index 0 is yesterday and index 1 is today
# Notice I used -1 for the day before yesterday b/c I wasn't sure what to do but I would like to include that in the buy condition

if (context.mDIvalues[1] > context.pDIvalues[1]) and (context.mDIvalues[1] > context.adxvalues[1]) and (context.mDIvalues[1] < context.mDIvalues[0]) and (context.mDIvalues[0] < context.mDIvalues[-1]):  
    order(sid(19920), 500)  
    log.debug('buy')  


elif (context.adxvalues[1] > context.mDIvalues[1]) and (context.pDIvalues[1] > context.mDIvalues[1]) and (context.pdivalues[1] < context.pDIvalues[0]) and (context.adxvalues[1] < context.adxvalues[0]):  
    order(sid(19920), -500)  
    log.debug('sell')  

log.debug('adx')  
log.debug(context.adx)  
log.debug('pDI')  
log.debug(context.pDI)  
log.debug('mDI')  
log.debug(context.mDI)  

Hello Justin,

I see you've put loads of work into this...but I thought it would be simpler to try your logic using the TA-Lib indicator library (see http://ta-lib.org/). To test current, day-1 and day-2 values I made the queue length 3.

P.

Clone Algorithm
30
Loading...
Backtest from to with initial capital
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
# Backtest ID: 528d61f11f4fe2202b41bce1
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.

Ha! Peter, you're the best. I know I'm terrible at this, but I'm obviously working through the process.... I appreciate your feedback and the indicator library resource. Very helpful. Maybe with the support of this community there's hope for me yet.....

Cheers,

Justin

Hello:

I am new to Python, coding in general, and quant finance, but am finding this site really fascinating so far. I watch commodity markets, and would like to try and run this algorithm on the continuous front month corn contract. The data is located on quandl at:

http://www.quandl.com/OFDP-Open-Financial-Data-Project/FUTURE_C1-CBOT-Corn-Futures-Continuous-Contract-1-C1-Front-Month

I read the section on importing quandl data, but was unable to figure out how to do this. I am not sure how to run it without the sid code. I know there is a corn etf, but I would rather not use that. If anyone could provide some advice, I would appreciate it.

Thanks,

Josh

Hello Josh,

I struggle a bit with 'fetch_csv'. I've got as far as reading the data:

def initialize(context):  
    context.sid = sid(8554)  
    fetch_csv('http://www.quandl.com/api/v1/datasets/OFDP/FUTURE_C1.csv?&trim_start=1959-07-01&trim_end=2013-11-20&sort_order=desc',  
              symbol      = 'Corn',  
              date_column = 'Date',  
              date_format = '%y/%m/%d',  
              pre_func    =  show_df)

def show_df(df):  
    print df.head()  
    return df

def handle_data(context, data):  
    pass  

P.

Thanks Peter, I will play around with this over the weekend.

Reviving an old post here... this code is fantastic and has been a huge help to me. Does the OP or anyone else know why the summing on lines 92-94 of the original code are not divided by context.window_length? I would imagine these averages need to be divided by an N rather than just be a sum.

Amending this produces a negligible difference in my backtest so I'm just wondering if this summation is intentional for the subsequent moving average calculation?

Hi, I have zero knowledge on algo program but I know well on DMI.

DMI has its problems too. For example, when stock price gap up, +DI cross above -DI at a stock price that cannot be filled and therefore traders must carefully use DMI in backtesting that may give wrong results. I wish I know how to read the algo program in collaborating a better DMI.

Is that really a problem though? Taking gaps into account is part of the advantage of DMI (and "true" range in general)

If a stock price is opened gap up, say closed 20 and open gap up 22, DMI may show buy signal at 20.80 but there is no 20.80 to buy since price already gap up at 22 opening. Thus, it will have a wrong result if not carefully track down the proper prices using DMI.

I think you're getting too granular if you're telling your algorithm to buy only at the exact price the DI lines cross (slippage would make that improbable in real trading anyway). The purpose of the ADX is to indicate a trend, thus if a price gaps up to 22 and the +DI line is now above the -DI line, I would take that as a valid entry signal because the trend has turned bullish (depending on ADX readings and other factors).

Is there a way we can add to print the ROC and ADX below the backtest?

has this strategy been ported to the Quantopian2 APIs? I tried cloning it but it won't build in its current form

Can any one please post a working code for the ADX here. None of the previous codes are compiling. I tried cloning and not able to build it.

Here it is.

Clone Algorithm
74
Loading...
Backtest from to with initial capital
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
# Backtest ID: 57cfb615e1982b12a6453521
There was a runtime error.

Hi Vladimir: Thank you very much for so fast reply. I will try to use this code and probably will be asking you for more help as I am new to Python. Thanks

dchdc">"njcd

Ok well number one: The post above me is ummm interesting. Also, given how many times the OG algorithm has been copied, I'm surprised that no one has bothered to check the leverage of this algorithm... It's totally out of control.

Clone Algorithm
18
Loading...
Backtest from to with initial capital
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
# Backtest ID: 596d268322cea75248e2b61f
There was a runtime error.

@Jacob it might be because of a difference between the Q platform 2013 and now. The original gives 193% returns and yours 3347%.

Anyways, I've tried using ADX in my algos (the talib version, not this implementation) and was unimpressed with it. Anybody gotten anything useful out of it?

@atiredmachine
It is most likely due to the fact that the starting capital is 1,000,000 and it is trading every minute
even when using :

order_target_percent(stock, 1.0)  

it still over exposes.
IMO Indicators are inherently pretty useless... I use them to determine when to decrease leverage and or pull out of the market entirely - thats it.

@Jacob I believe Quantopian used to have a dropdown for daily or minute mode. This algo was probably written for daily mode.

My results using Vladimir's code is nowhere near as good as the original post. Basically buy when adx>25 and p>n, sell when adx>25 and n>p

Clone Algorithm
8
Loading...
Backtest from to with initial capital
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
# Backtest ID: 596e4721b30096525660b4a4
There was a runtime error.

Daniel,

May be there is sence to try using ADX this way:

# ADX_trader 

import talib

def initialize(context):  
    schedule_function(ADX_trader, date_rules.every_day(), time_rules.market_close(minutes = 35))  
    set_commission(commission.PerShare(cost=0.001, min_trade_cost=0))

def ADX_trader(context, data):  
    # -------------------------------------  
    stk, bnd = symbol('qqq'), symbol('tlt')  
    period = 33  
    # -------------------------------------  
    if get_open_orders(): return 

    H = data.history(stk,'high', 2*period, '1d').dropna()  
    L = data.history(stk,'low', 2*period, '1d').dropna()  
    C = data.history(stk,'price', 2*period, '1d').dropna()    

    ta_ADX = talib.ADX(H, L, C, period)  
    ta_nDI = talib.MINUS_DI(H, L, C, period)  
    ta_pDI = talib.PLUS_DI(H, L, C, period)  
    ADX, nDI, pDI = ta_ADX[-1], ta_nDI[-1], ta_pDI[-1]

    record( ADX = ADX, nDI = nDI, pDI = pDI) 

    if nDI < pDI and ADX > 10:  
        wt_stk, wt_bnd = 0.8, 0.2  
    elif nDI > pDI and ADX > 10 :  
        wt_stk, wt_bnd = 0.2, 0.8  
    elif ADX < 0:  
        wt_stk, wt_bnd = 0.2, 0.8  
    else: return    

    if all(data.can_trade([stk, bnd])):  
        order_target_percent(stk, wt_stk)  
        order_target_percent(bnd, wt_bnd) 

'''

100000

START  
06/01/2007  
END  
07/17/2017

'''

Wow Vladimir, your version performed 2x better than the benchmark. I guess going 100% long or short on QQQ isn't the greatest approach (like I originally did), since it is such an uptrending stock. Definitely like your 80/20 split method more. Thank you for commenting

Can anyone help creating a sample source code for me to look into soybean oil futures 2nd continuous contract month using ADX technical trend indicator? If can, please include the stop and reverse trades with minimum 1 lot, a 15-minute high low close data with ADX lines -- +DI, -DI and ADX lines. Many thanks.