Closed LooOOooM closed 6 years ago
@LooOOooM Are you using this for crypto? Did you set the precision? Could be a rounding error where the close = high = open = low, because I see nothing in the code that could cause this other than...
@anandanand84 The approximateEquals
function has a hard coded precision of 4 and for crypto this could give the above result if the precision is expected to be 8 to 10? Best guess without seeing some data
@LooOOooM can you send me a sample data for this issue. @JMoli Thanks, I'll fix the precision
Hallo Guys, and Thanks for the very fast replay. 1) Yes I am using this for crypto (XTB) 2) No I did not set precision, just read about this option the first time. Just tried to set it to "10", without any changes. Can anybody point me to more info about it as I dont understand its value range 1-21. 3) Sampledata: sampledata = { open: [961.19, 962.09, 962.10] close: [961.25, 962.09, 961.14] high: [961.63, 962.09, 962.10] low: [961.19, 962.09, 961.14] }
THANKS GUYS
@LooOOooM In your first example it looks like all the numbers were approximated to ~967 which would make it a doji and make them both lying? It seems odd that doji would not be truthy here as well as it only considers the open and close.
I guess maybe add a check to doji to make sure Close != Low and Close != High unless High = Low
I think the problem is the approximation (which I believe to be necessary). If we remove the approximation and say for example the high must equal the close exactly that would fix this problem but since this really doesn't reflect real world market conditions as a price difference of < .5 would in my book be considered a doji, we would need to agree on some magic Doji percentage that would mark a doji (where approximate high = approximate low = approximate close = approximate open) from a dragonfly / gravestone (where approximate open = approximate high = approximate close but approximate low is greater than an approximate measure separating it from a regular doji) ... which could be subjective and problematic depending on the market, and still most likely have edge cases where doji and the dragonfly / gravestone trigger together.
How different is the open from the close before it is no longer a doji? If we can agree on this in an quantitive measure maybe we could add that same logic to the dragonfly / gravestone... How different is the low from the high... etc... If I haven't gotten too metaphysical...
Quite fascinating really, I would be curious as to how other libraries approach this problem as I am sure it is universal, but this truly is one of those tiny nuances easily overlooked and difficult to quantify that can make a profitable difference to trading algorithm considering how important a single doji can be.
...or maybe i'm just over thinking it
Interesting. Static 10% seems like an Occam/Rand's razor solution. The only thing I noticed with this solution is that a high = open = low = close will not trigger a doji. The more I think about this the more I think that may be correct as perhaps it should be classified as something different as it more closely reflects low market volume as opposed to a change in market trends.
I will get to a PR shortly and add this and the other changes.
@JMoli I think so too that the definition of dojis should bebased on percentage rather then .x value, as the size of the candle is relativ to a lot of things like, pair, timeframe, etc.
Here's what i came up with to check candle patterns. It may not be very pretty, but it's really simple, is percentage based so it can be used perfectly with super low price pairs and is pretty accurate. The ratios and such aren't perfect yet, but when testing it against the functions in this library with backtest data, it's proven to increase my algo's win/loss ratio by ~5%.
function checkCandle(tick){
var open = tick.open;
var high = tick.high;
var low = tick.low;
var close = tick.close;
var vma = tick.vma2;
var rma = tick.rm2;
var vChange = tick.volume / vma;
var range = close / open;
var hc = high / close;
var ol = open / low;
var ho = high / open;
var cl = close / low;
if(range / rma >= 4.00 && vChange >= 2){ //bullish breakout candle
return {direction : 'up', type: 'breakout', cond : 4}
}else if(range <= 1.0005 && range >= 0.9995){ //doji's
if(hc < 1.0010 && ol < 1.0010){ //doji
if(range == 1){ //no movement
return {direction: 'flat' , type: 'flat', cond : -1}
};
return {direction : 'flat', type: 'doji' , cond : -1}
}else if(hc >= 1.0010 && ol >= 1.0010){ //long-legged doji
return {direction : 'flat', type: 'long-doji', cond : 1}
}else if(hc >= 1.0010 && ol < 1.0010){ //gravestone doji
return {direction : 'flat', type: 'gravestone', cond : -2}
}else if(hc < 1.0010 && ol >= 1.0010){ //dragonfly doji
return {direction : 'flat', type: 'dragonfly', cond : 2}
}else{
return
};
}else if(range > 1.0005 && range <=1.0020){ // positive hammer's
if(hc <= 1.0005 && ol >= 1.0025){ //hammer
return {direction : 'up', type: 'hammer', cond : 2}
}else if(hc >= 1.0025 && ol <= 1.0005){ // inverted hammer
return {direction : 'up', type: 'inverted hammer', cond : 1}
}else if(hc >= 1.0020 && ol >= 1.0020){ //spinning top
return {direction : 'up', type: 'spinning top', cond : 1}
}else{
return {direction : 'up', type: 'small body', cond : 1}
};
}else if(range < 0.9995 && range >= 0.9980){ //negative hammer's
if(ho <= 1.0005 && cl >= 1.0025){ //black hammer
return {direction : 'down', type: 'black hammer', cond : -2}
}else if(ho >= 1.0025 && cl <= 1.0005){ // inverted black hammer
return {direction : 'down', type: 'inverted black hammer', cond : -1}
}else if(ho >= 1.0020 && cl >= 1.0020){ //black spinning top
return {direction : 'down', type: 'black spinning top', cond : -2}
}else{
return {direction : 'down', type: 'black small body', cond : -1}
};
}else if(range > 1.0020){ //positive big candles
if(hc <= 1.0002 && ol <= 1.0002){ //positive marubozu
return {direction : 'up', type: 'marubozu', cond : 3}
}else{
if(hc >= 1.0050 && ol >= 1.0050){// positive big spinner
return {direction : 'up', type: 'big spinner', cond : 1}
}else if(hc >= 1.0050){ //positive buy spike
return {direction : 'up', type: 'buy spike', cond : 2}
}else if(ol >= 1.0050){ //positive sell spike
return {direction : 'up', type: 'sell spike', cond : 2}
}else{ //positive normal
return {direction : 'up', type: 'big candle', cond : 3}
};
};
}else if(range < 0.9980){ //negative big candles
if(ho <= 1.0002 && ol <= 1.0002){ //negative marubozu
return {direction : 'down', type: 'black marubozu', cond : -3}
}else{
if(ho >= 1.0050 && cl >= 1.0050){// negative big spinner
return {direction : 'down', type: 'big black spinner', cond : -3}
}else if(ho >= 1.0050){ //negative buy spike
return {direction : 'down', type: 'black buy spike', cond : -1}
}else if(cl >= 1.0050){ //negative sell spike
return {direction : 'down', type: 'black sell spike', cond : 2}
}else{ //negative normal
return {direction : 'down', type: 'black big body', cond : -2}
};
};
}else{
return
};
};
for reference: vma is a slow period volume moving average. rma is a slow period range moving average, calculated by subtracting each candle's low from it's high (high-low), then feeding that number to the moving average calculation. I hope this helps someone out there.
DragonFlyDoji & GraveStoneDoji always trigger together.
Candle (3): O: 967.21 / H: 967.21 / L: 966.74 / C: 967.00 dragonFlyDoji? :true graveStoneDoji? :true
.... Looks like graveStoneDoji is lying here.
Candle (46): O: 964.11 / H: 964.11 / L: 964.11 / C: 964.11 doji? :true dragonFlyDoji? :true graveStoneDoji? :true
Looks like both (dragonFlyDoji & graveStoneDoji) are lying as this is a doji only.