Gekko Forum
[SHARE] PSAR Indicator and Strat - Printable Version

+- Gekko Forum (https://forum.gekko.wizb.it)
+-- Forum: Gekko (https://forum.gekko.wizb.it/forum-13.html)
+--- Forum: Strategy Development (https://forum.gekko.wizb.it/forum-12.html)
+--- Thread: [SHARE] PSAR Indicator and Strat (/thread-57291.html)



[SHARE] PSAR Indicator and Strat - PatTrends - 06-27-2018

Hey all,

I've really been enjoying Gekko lately and thought I would share a PSAR Indicator/Strat I wrote.

PSAR, by itself, is an awful strategy - particularly in consolidating markets. The included strategy is provided more as an example, and simply buys and sells on trend reversals. That said, PSAR is a great way to set dynamic stop-losses (as opposed to static values or percentage-based trailing stop-losses).

While I didn't specifically port the Tulip code, I did verify my indicator generates the same results. I also heavily commented the indicator so newer users can try to figure out what its doing. If you can improve my code, let me know!

PSAR.toml

Code:
acceleration = 0.02
maximum = 0.2
persistence = 2



strategies/PSAR.js

Code:
// PSAR strat
// PT 06/26/18

// let's create our own method
var method = {};

// prepare everything our method needs
method.init = function() {
 this.name = 'PSAR';
 this.inTrade = false;

 this.requiredHistory = 100;

 // define the indicators we need
 this.addIndicator('psar', 'PSAR', this.settings);


};

// what happens on every new candle?
method.update = function(candle) {
 // nothing!
};


method.log = function(candle) {
 // nothing!
};

method.check = function() {
 var psar = this.indicators.psar;
 var trend = psar.trend;
 var trendDuration = psar.duration;
 // var psarResult = psar.psar;


 //Sell Signal
 if(trend == "down" && trendDuration >= this.settings.persistence && this.inTrade){
   this.advice('short');
   this.inTrade = false;

 }

 //Buy Signal
 if(trend == "up" && trendDuration >= this.settings.persistence && !this.inTrade){
   this.advice('long');
   this.inTrade = true;
 }

};

module.exports = method;



indicators/PSAR.js

Code:
//PSAR
//PT-06/26/2018

var Indicator = function(config) {
 this.input = 'candle';
 this.acceleration = config.acceleration;
 this.accelerationStep = config.acceleration;
 this.persistence = config.persistence;
 this.maximum = config.maximum;
 this.psar = null;
 this.initPsar = null;
 this.psarEpAcc = null;
 this.extremePoint = null;
 this.trend = null;
 this.previousTrend = null;
 this.duration = 0;

 this.candleHistory = [];

};


Indicator.prototype.update = function(candle) {

 this.candleHistory.push(candle);

 if(this.candleHistory.length >= 3) {

   //Define candles
   // var candle = this.candleHistory[2];
   var previousCandle = this.candleHistory[1];
   var prevPreviousCandle = this.candleHistory[0];

   //first run
   if (this.psar === null) {
     this.extremePoint = prevPreviousCandle.low;
     this.psar = prevPreviousCandle.high;
     this.previousTrend = 'down';
   }


   //PSAR EQUATION
   this.psarEpAcc = (this.psar - this.extremePoint) * this.acceleration;

   //PAST TREND LOGIC
   if (this.previousTrend == 'down') {

     //calculate initial psar
     this.initPsar = Math.max((this.psar - this.psarEpAcc), previousCandle.high, prevPreviousCandle.high);

     //calculate PSAR
     this.psar = (candle.high < this.initPsar) ? this.initPsar : this.extremePoint;

     //increase duration count
     this.duration++;

   }

   if (this.previousTrend == 'up') {

     //calculate initial psar
     this.initPsar = Math.min((this.psar - this.psarEpAcc), previousCandle.low, prevPreviousCandle.low);

     //calculate PSAR
     this.psar = (candle.low > this.initPsar) ? this.initPsar : this.extremePoint;

     //increase duration count
     this.duration++;

   }

   //Define trend
   this.trend = (this.psar > candle.close) ? 'down' : 'up';

   //CURRENT TREND LOGIC
   if(this.trend == 'down'){
     //calculate Extreme point
     this.extremePoint = Math.min(this.extremePoint, candle.low);
   }
   if(this.trend =='up'){
     //calculate Extreme point
     this.extremePoint = Math.max(this.extremePoint, candle.high);
   }

   //UPDATE LOGIC
   //If the trend stays the same and the extreme point doesn't equal the previous extreme point and the acceleration factor is less than the maximum factor...
   if (this.trend == this.previousTrend && this.extremePoint != this.previousExtremePoint && this.acceleration <= this.maximum) {

     //Increment the acceleration value
     this.acceleration += this.accelerationStep;
   }

   //If the trend stays the same and the extreme point value stays the same...
   if (this.trend == this.previousTrend && this.extremePoint == this.previousExtremePoint) {
     //Acceleration stays the same
   }

   // If the current trend doesn't equal the previous trend...
   if (this.trend != this.previousTrend) {

     //Set the acceleration to the initial value
     this.acceleration = this.accelerationStep;

     //reset duration count
     this.duration = 0;
   }

   //set values/array for next run
   this.previousExtremePoint = this.extremePoint;
   this.previousTrend = this.trend;
   this.candleHistory.shift();
 }

};

module.exports = Indicator;