Long Term Bollinger Band Breakout Strategy for ThinkorSwim

Zachc

Member
2019 Donor
I am always looking for a nice long term system that is adept at entering into long term trends. I don't have time for day trading or even swing trading for that matter.

I was listening to the ChatwithTraders podcast which I highly recommend to anyone that has not listened to check out the huge back catalog Aaron has encompassing every market trading strategy and mindset you can think of. This month's episode is with Nick Radge which they took the time to outline Nick's process on building trading strategies which were very enlighting for a novice.

Nick outlined a simple trend-following the strategy he developed backtested and published years ago in his book Unholy grails he uses in his retirement portfolio. The strategy is long-only and is perfect for a long term set it and forget it type of strategy. Which would be perfect for my 2-year-old daughters UTMA account.

Anyways TLDR: I made a video for everyone explaining the strategy and showing some example trades.

Strategy Parameters
  • This is a long-only strategy
  • Buy and Sell the day after the signal at the open
  • Regime filter used to halt trading when the index is below the 200 SMA
  • Rate of change filters out any moves that are less than 10% looking back 20 periods
  • Added an ATR Trailing Stop to weed out the bigger losses due to the BBands expanding really wide during large trends
Bollinger Band Settings
  • Weekly Time Frame
  • 100 Period
  • Upper band 2 stdv
  • Lower band -1 stdv
  • SMA Average
BollBand_Long Breakout
https://tos.mx/nL28ZR
BollBand_Short Breakout
https://tos.mx/EadCK8
Weekly Scan for new positions
https://tos.mx/jTYMAq
Daily Scan for new positions
https://tos.mx/YZXOS6

3pbQjZ5.png

Typo on exactly in the image ugh.

QpmCuWe.png


Code:
##Nick Radge Bollinger Band Breakout Strat
##
##Basic Strategy used on a Daily, Weekly, Monthly timeframe.
# 1) Bollinger bands Period 100 days
# 2) Boll bands set to 2 standard deviation
# 3) Buy on the open day after the signal
# 4) Bottom Bollinger band set to -1 stdv
# 6) Sell when price closes below this level on the following day
# 7) Use a regime filter to gague the overall market sentimate
#    Gaged by the 200day MA on then index that you can select from the drop down.  SPX is default.

declare hide_on_intraday;
input roc = 20;
input bbPeriod = 100;
input bbUpper = 2;
input bbLower = -1;
input bbAvg = AverageType.SIMPLE;
input market = {default SPX, NDX, RUT, DJX};
Input Market_200Day_MA = 40;

## Indicator
def bbBreakUp = close > BollingerBands(close, length = bbPeriod, "num dev up" = bbUpper, "average type" = bbAvg, "num dev dn" = bbLower).UpperBand;
def bbBreakDown = close < BollingerBands(price = open, length = bbPeriod, "num dev dn" = bbLower, "num dev up" = bbUpper, "average type" = bbAvg).LowerBand;

## Regime Filter
#Is the market this stock is apart of above the 200 day MA
#8/13/19 Updated to 40 periods for the weekly time frame as the default credit mc01439

def length = Market_200Day_MA;
def RF = SimpleMovingAvg(close(symbol = market), length);

plot closeMA = close(symbol = market) < RF;

def marClose = close(market);
AddLabel(1, Concat("Index: ", Concat(market, Concat(" " + marClose, " 200SMA= " + RF))), if marClose > RF
  then Color.GREEN
  else Color.RED);

## Confirmation rate of change
def rate = RateOfChange(roc);

########################################################################
## Trailing Stop

input trailType = {default modified, unmodified};
input ATRPeriod = 5;
input ATRFactor = 3.5;
input firstTrade = {default long, short};

assert(ATRFactor > 0, "'atr factor' must be positive: " + ATRFactor);

def HiLo = Min(high - low, 1.5 * Average(high - low, ATRPeriod));
def HRef = if low <= high[1]
  then high - close[1]
  else (high - close[1]) - 0.5 * (low - high[1]);
def LRef = if high >= low[1]
  then close[1] - low
  else (close[1] - low) - 0.5 * (low[1] - high);
def ATRMod = ExpAverage(Max(HiLo, Max(HRef, LRef)), 2 * ATRPeriod - 1);
def loss = ATRFactor * ATRMod;
#  case unmodified:
#    loss = ATRFactor * ATR(high, close, low, ATRPeriod);


def state = {default init, long, short};
def trail;

switch (state[1]) {
  case init:
    if (!IsNaN(loss)) {
      switch (firstTrade) {
        case long:
          state = state.long;
          trail =  close - loss;
        case short:
          state = state.short;
          trail = close + loss;
      }
    } else {
      state = state.init;
      trail = Double.NaN;
    }

  case long:
    if (close > trail[1]) {
      state = state.long;
      trail = Max(trail[1], close - loss);
    } else {
      state = state.short;
      trail = close + loss;
    }
  case short:
    if (close < trail[1]) {
      state = state.short;
      trail = Min(trail[1], close + loss);
    } else {
      state = state.long;
      trail =  close - loss;
    }
}

plot TrailingStop = trail;
TrailingStop.SetPaintingStrategy(PaintingStrategy.POINTS);
TrailingStop.DefineColor("Buy", GetColor(0));
TrailingStop.DefineColor("Sell", GetColor(1));
TrailingStop.AssignValueColor(if state == state.long
  then TrailingStop.color("Sell")
  else TrailingStop.color("Buy"));

plot cross = close crosses below trailingstop;
cross.setPaintingStrategy(paintingStrategy.BOOLEAN_ARROW_DOWN);
#end


###Plots###
plot upper = BollingerBands(close, length = bbPeriod, "num dev up" = bbUpper, "average type" = bbAvg, "num dev dn" = bbLower).UpperBand;
plot lower = BollingerBands(close, length = bbPeriod, "num dev up" = bbLower, "average type" = bbAvg, "num dev dn" = bbLower).LowerBand;
plot buySignal = bbBreakUp and rate > 10 and marClose > RF;
    buySignal.SetpaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
    buySignal.SetLineWeight(2);
    buySignal.SetDefaultColor(Color.GREEN);
plot sellSignal = bbBreakDown;
    sellSignal.SetpaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_Down);
    sellSignal.SetLineWeight(2);
    sellSignal.SetDefaultColor(Color.Red);

### Order Entry ###
#8/13/19 changed the index to [-1] on the open variable to ensure the order is placed on the open of the following day credit: mc01439

AddOrder(condition = buySignal, type = OrderType.BUY_TO_OPEN, price = open[-1], name = "bbBreak_LE");
AddOrder(condition = bbBreakDown, type = OrderType.SELL_TO_CLOSE, price = open[-1], name = "bbBreak_LX");
AddOrder(condition = cross, type = OrderType.SELL_TO_CLOSE, price = open[-1], name = "TrailStop");
 
Last edited:

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

If you are interested in and have an account that can go short equities, futures forex, etc. Here is the study reversed which will allow you to go short. Just add this study on top of the long version.

Also Added daily and weekly scans to the main post link section.


Code:
##Nick Radge Bollinger Band Breakout Strat short version
##
##Basic Strategy used on a Daily, Weekly timeframe.
# 1) Bollinger bands Period 100 days
# 2) Boll bands set to 1 standard deviation
# 3) Buy on the open day after the signal
# 4) Bottom Bollinger band set to -2 stdv
# 6) Sell when price closes above the top band on the following day
# 7) Use a regime filter to gague the overall market sentimate
# 8) Gaged by the 200day MA on then index that you can select from the drop down.  SPX is default.
# 9) 3.5 ATR trailing stop on by defult adjust according to your strategy.

input roc = 20;
input bbPeriod = 100;
input bbUpper = 1;
input bbLower = -2;
input bbAvg = AverageType.SIMPLE;
input market = {default SPX, NDX, RUT, DJX};
Input Market_200Day_MA = 40;

## Indicator
def bbBreakUp = close crosses above BollingerBands(close, length = bbPeriod, "num dev up" = bbUpper, "average type" = bbAvg, "num dev dn" = bbLower).UpperBand;
def bbBreakDown = close crosses below BollingerBands(price = open, length = bbPeriod, "num dev dn" = bbLower, "num dev up" = bbUpper, "average type" = bbAvg).LowerBand;
def bbShortUp = close crosses above BollingerBands(close, length = bbPeriod, "num dev up" = bbUpper, "average type" = bbAvg, "num dev dn" = bbLower).LowerBand;

## Regime Filter
#Is the market this stock is apart of above the 200 day MA
def length = Market_200Day_MA;
def RF = SimpleMovingAvg(close(symbol = market), length);

def marClose = close(market);
AddLabel(1, Concat("Index: ", Concat(market, Concat(" " + marClose, " 200SMA= " + RF))), if marClose > RF
  then Color.GREEN
  else Color.RED);

## Confirmation rate of change
def rate = RateOfChange(roc);

########################################################################
## Trailing Stop

input trailType = {default modified, unmodified};
input ATRPeriod = 5;
input ATRFactor = 3.5;
input firstTrade = {default short, long};

Assert(ATRFactor > 0, "'atr factor' must be positive: " + ATRFactor);

def HiLo = Min(high - low, 1.5 * Average(high - low, ATRPeriod));
def HRef = if low <= high[1]
  then high - close[1]
  else (high - close[1]) - 0.5 * (low - high[1]);
def LRef = if high >= low[1]
  then close[1] - low
  else (close[1] - low) - 0.5 * (low[1] - high);
def ATRMod = ExpAverage(Max(HiLo, Max(HRef, LRef)), 2 * ATRPeriod - 1);
def loss;
switch (trailType) {
case modified:
    loss = ATRFactor * ATRMod;
case unmodified:
    loss = ATRFactor * Average(TrueRange(high,  close,  low),  ATRPeriod);
}

def state = {default init, long, short};
def trail;

switch (state[1]) {
case init:
    if (!IsNaN(loss)) {
        switch (firstTrade) {
        case long:
            state = state.long;
            trail =  close - loss;
        case short:
            state = state.short;
            trail = close + loss;
    }
    } else {
        state = state.init;
        trail = Double.NaN;
    }
case long:
    if (close > trail[1]) {
        state = state.long;
        trail = Max(trail[1], close - loss);
    } else {
        state = state.short;
        trail = close + loss;
    }
case short:
    if (close < trail[1]) {
        state = state.short;
        trail = Min(trail[1], close + loss);
    } else {
        state = state.long;
        trail =  close - loss;
    }
}

plot TrailingStop = trail;
TrailingStop.SetPaintingStrategy(PaintingStrategy.POINTS);
TrailingStop.DefineColor("Buy", GetColor(0));
TrailingStop.DefineColor("Sell", GetColor(1));
TrailingStop.AssignValueColor(if state == state.long
  then TrailingStop.Color("Sell")
  else TrailingStop.Color("Buy"));

plot cross = close crosses TrailingStop;
cross.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
#end


###Plots###
plot upper = BollingerBands(close, length = bbPeriod, "num dev up" = bbUpper, "average type" = bbAvg, "num dev dn" = bbLower).UpperBand;
plot lower = BollingerBands(close, length = bbPeriod, "num dev up" = bbLower, "average type" = bbAvg, "num dev dn" = bbLower).LowerBand;
plot buySignal = bbBreakUp;
buySignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
buySignal.SetLineWeight(2);
buySignal.SetDefaultColor(Color.GREEN);
plot sellSignal = bbBreakDown and rate < 10 and marClose < RF;
sellSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
sellSignal.SetLineWeight(2);
sellSignal.SetDefaultColor(Color.RED);

### Order Entry ###

AddOrder(condition = bbBreakUp, type = OrderType.BUY_TO_CLOSE, price = open[-1], name = "bbBreak_SX");
AddOrder(condition = bbBreakDown, type = OrderType.SELL_TO_OPEN, price = open[-1], name = "bbBreak_SE");
AddOrder(condition = cross, type = OrderType.BUY_TO_CLOSE, price = open[-1], name = "TrailStop");
 
Last edited:
@Zachc Thanks for putting the work in on Nick Radge's study. This is a quality posting!
I follow him on Twitter and get his newsletter.
An excellent person for anyone to learn Trend Following from!
 
@Zachc Thanks for putting the work in on Nick Radge's study. This is a quality posting!
I follow him on Twitter and get his newsletter.
An excellent person for anyone to learn Trend Following from!

I couldn't agree more about Nick he is a wealth of knowledge and provides very detailed instructions where a lot of the other guys only go into vague generalities about trading systems and how they develope them. I will be going through some of the other strategies over time. Just wanted to share this one since I currently trade with it.
 
The way you wrote the order code has the trade open at the open the day the price broke the Upper band 2 stdv. This is hindsight and will cause issues with live order entries.

AddOrder(condition = buySignal, type = OrderType.BUY_TO_OPEN, price = open, name = "bbBreak_LE");
AddOrder(condition = bbBreakDown, type = OrderType.SELL_TO_CLOSE, price = open, name = "bbBreak_LX");
AddOrder(condition = cross, type = OrderType.SELL_TO_CLOSE, price = open, name = "TrailStop");

If you want to entry the day after the signal at the open may want to consider the following;

AddOrder(condition = buySignal, type = OrderType.BUY_TO_OPEN, price = open[-1], name = "bbBreak_LE");
AddOrder(condition = bbBreakDown, type = OrderType.SELL_TO_CLOSE, price = open[-1], name = "bbBreak_LX");
AddOrder(condition = cross, type = OrderType.SELL_TO_CLOSE, price = open[-1], name = "TrailStop");
 
Last edited:
I am always looking for a nice long term system that is adept at entering into long term trends. I don't have time for day trading or even swing trading for that matter.

I was listening to the ChatwithTraders podcast which I highly recommend to anyone that has not listened to check out the huge back catalog Aaron has encompassing every market trading strategy and mindset you can think of. This month's episode is with Nick Radge which they took the time to outline Nick's process on building trading strategies which were very enlighting for a novice.

Nick outlined a simple trend-following the strategy he developed backtested and published years ago in his book Unholy grails he uses in his retirement portfolio. The strategy is long-only and is perfect for a long term set it and forget it type of strategy. Which would be perfect for my 2-year-old daughters UTMA account.

Anyways TLDR: I made a video for everyone explaining the strategy and showing some example trades.

Strategy Parameters
  • This is a long-only strategy
  • Buy and Sell the day after the signal at the open
  • Regime filter used to halt trading when the index is below the 200 SMA
  • Rate of change filters out any moves that are less than 10% looking back 20 periods
  • Added an ATR Trailing Stop to weed out the bigger losses due to the BBands expanding really wide during large trends
Bollinger Band Settings
  • Weekly Time Frame
  • 100 Period
  • Upper band 2 stdv
  • Lower band -1 stdv
  • SMA Average


3pbQjZ5.png

Typo on exactly in the image ugh.

QpmCuWe.png


Code:
##Nick Radge Bollinger Band Breakout Strat
##
##Basic Strategy used on a Daily, Weekly, Monthly timeframe.
# 1) Bollinger bands Period 100 days
# 2) Boll bands set to 2 standard deviation
# 3) Buy on the open day after the signal
# 4) Bottom Bollinger band set to -1 stdv
# 6) Sell when price closes below this level on the following day
# 7) Use a regime filter to gague the overall market sentimate
#    Gaged by the 200day MA on then index that you can select from the drop down.  SPX is default.

declare hide_on_intraday;
input roc = 20;
input bbPeriod = 100;
input bbUpper = 2;
input bbLower = -1;
input bbAvg = AverageType.SIMPLE;
input market = {default SPX, NDX, RUT, DJX};


## Indicator
def bbBreakUp = close > BollingerBands(close, length = bbPeriod, "num dev up" = bbUpper, "average type" = bbAvg, "num dev dn" = bbLower).UpperBand;
def bbBreakDown = close < BollingerBands(price = open, length = bbPeriod, "num dev dn" = bbLower, "num dev up" = bbUpper, "average type" = bbAvg).LowerBand;

## Regime Filter
#Is the market this stock is apart of above the 200 day MA

def RF = SimpleMovingAvg(close(symbol = market), length = 200);

plot closeMA = close(symbol = market) < RF;

def marClose = close(market);
AddLabel(1, Concat("Index: ", Concat(market, Concat(" " + marClose, " 200SMA= " + RF))), if marClose > RF
  then Color.GREEN
  else Color.RED);

## Confirmation rate of change
def rate = RateOfChange(roc);

########################################################################
## Trailing Stop

input trailType = {default modified, unmodified};
input ATRPeriod = 5;
input ATRFactor = 3.5;
input firstTrade = {default long, short};

assert(ATRFactor > 0, "'atr factor' must be positive: " + ATRFactor);

def HiLo = Min(high - low, 1.5 * Average(high - low, ATRPeriod));
def HRef = if low <= high[1]
  then high - close[1]
  else (high - close[1]) - 0.5 * (low - high[1]);
def LRef = if high >= low[1]
  then close[1] - low
  else (close[1] - low) - 0.5 * (low[1] - high);
def ATRMod = ExpAverage(Max(HiLo, Max(HRef, LRef)), 2 * ATRPeriod - 1);
def loss = ATRFactor * ATRMod;
#  case unmodified:
#    loss = ATRFactor * ATR(high, close, low, ATRPeriod);


def state = {default init, long, short};
def trail;

switch (state[1]) {
  case init:
    if (!IsNaN(loss)) {
      switch (firstTrade) {
        case long:
          state = state.long;
          trail =  close - loss;
        case short:
          state = state.short;
          trail = close + loss;
      }
    } else {
      state = state.init;
      trail = Double.NaN;
    }

  case long:
    if (close > trail[1]) {
      state = state.long;
      trail = Max(trail[1], close - loss);
    } else {
      state = state.short;
      trail = close + loss;
    }
  case short:
    if (close < trail[1]) {
      state = state.short;
      trail = Min(trail[1], close + loss);
    } else {
      state = state.long;
      trail =  close - loss;
    }
}

plot TrailingStop = trail;
TrailingStop.SetPaintingStrategy(PaintingStrategy.POINTS);
TrailingStop.DefineColor("Buy", GetColor(0));
TrailingStop.DefineColor("Sell", GetColor(1));
TrailingStop.AssignValueColor(if state == state.long
  then TrailingStop.color("Sell")
  else TrailingStop.color("Buy"));

plot cross = close crosses below trailingstop;
cross.setPaintingStrategy(paintingStrategy.BOOLEAN_ARROW_DOWN);
#end


###Plots###
plot upper = BollingerBands(close, length = bbPeriod, "num dev up" = bbUpper, "average type" = bbAvg, "num dev dn" = bbLower).UpperBand;
plot lower = BollingerBands(close, length = bbPeriod, "num dev up" = bbLower, "average type" = bbAvg, "num dev dn" = bbLower).LowerBand;
plot buySignal = bbBreakUp and rate > 10 and marClose > RF;
    buySignal.SetpaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
    buySignal.SetLineWeight(2);
    buySignal.SetDefaultColor(Color.GREEN);
plot sellSignal = bbBreakDown;
    sellSignal.SetpaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_Down);
    sellSignal.SetLineWeight(2);
    sellSignal.SetDefaultColor(Color.Red);

AddOrder(condition = buySignal, type = OrderType.BUY_TO_OPEN, price = open, name = "bbBreak_LE");
AddOrder(condition = bbBreakDown, type = OrderType.SELL_TO_CLOSE, price = open, name = "bbBreak_LX");
AddOrder(condition = cross, type = OrderType.SELL_TO_CLOSE, price = open, name = "TrailStop");

One more thought - if you want the 200 day simple moving average for the index you should consider this change if using higher than a one day chart.

Line #25
## Regime Filter
#Is the market this stock is apart of above the 200 day MA = 40 Bars for the weekly chart
Input Market_200Day_MA = 40; #200/5
def length = Market_200Day_MA;

def RF = SimpleMovingAvg(close(symbol = market), length);
 

Attachments

  • 3pbQjZ5.png
    3pbQjZ5.png
    166 KB · Views: 320
  • QpmCuWe.png
    QpmCuWe.png
    132.4 KB · Views: 320
@mc01439
The way you wrote the order code has the trade open at the open the day the price broke the Upper band 2 stdv. This is hindsight and will cause issues with live order entries.

AddOrder(condition = buySignal, type = OrderType.BUY_TO_OPEN, price = open, name = "bbBreak_LE");
AddOrder(condition = bbBreakDown, type = OrderType.SELL_TO_CLOSE, price = open, name = "bbBreak_LX");
AddOrder(condition = cross, type = OrderType.SELL_TO_CLOSE, price = open, name = "TrailStop");

If you want to entry the day after the signal at the open may want to consider the following;

AddOrder(condition = buySignal, type = OrderType.BUY_TO_OPEN, price = open[-1], name = "bbBreak_LE");
AddOrder(condition = bbBreakDown, type = OrderType.SELL_TO_CLOSE, price = open[-1], name = "bbBreak_LX");
AddOrder(condition = cross, type = OrderType.SELL_TO_CLOSE, price = open[-1], name = "TrailStop");
One more thought - if you want the 200 day simple moving average for the index you should consider this change if using higher than a one day chart.

Line #25
## Regime Filter
#Is the market this stock is apart of above the 200 day MA = 40 Bars for the weekly chart
Input Market_200Day_MA = 40; #200/5
def length = Market_200Day_MA;

def RF = SimpleMovingAvg(close(symbol = market), length);

Hey @mc01439 , thanks! I absolutely missed adding the [-1] index to the open on the order entry. Code has been updated across the board.

Also with the MA filter, I see what you did there that will make it much more accurate when moving between time frames which I frequently do. Something so simple can make such a huge difference. Thanks for all the input!
 
thank you, listened to the same interview and can't wait to backtest.. unfortunately I haven't learned to code yet so this is much appreciated!
 
related question if you will: did you cut out the adaptive trail stop (18-20% in bull market, 10% in bear)? If so, if it's not too much trouble, what code would I need to input and change?
 
I ended up implementing a trailing ATR stop into the strategy which seems to work just fine. I am currently working through backtesting with Bollinger Band Stops as well as ATR 5,3.5. I am also going to work in static portfolio sizing right now I am experimenting with $10,000 account at a 5% which has helped keep some of the losses at a minimum.
 
@tibby42 I just checked those links and they are working correctly. Please make sure you are copying the link and using the open shared item at the top right of the ThinkorSwim platform.
 
@Zachc it would be exciting to hear your results. Thanks for checking the links, I just tried them on my phone and they work, strangely this afternoon on my pc I clicked on more than one and got a site 404 kind of thing, maybe the site fixed it? Either way no matter thx again
 
@tibby42 Think or swim is getting an update this weekend so most likely it was due to their update activities. I actually forgot about the 18-20-10 rule he had mentioned. I do have the bull bear 200 day ma coded in so that trades are blocked in a bear market and the inverse in the bearish strat that is indicated by the red arrow at the low in the image above. As soon as I have a meaningful amount of data to share I will post it in the thread.
-cheers
 

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
296 Online
Create Post

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top