coin_alerts/Patterns.cs
2025-01-19 11:45:51 +05:30

200 lines
6.6 KiB
C#

using BinanceExchange.API.Models.Response;
public static class Patterns{
public static bool GetTGOR(List<KlineCandleStickResponse> responses, int curIndex){
if(curIndex < 10){
return false;
}
int greenCount =0;
for(int i=curIndex-4; i <= curIndex; i++){
if(responses[i].Close < responses[i].Open){
if(greenCount > 2){
//Red after 3 greens
int bullRunFlag = 0;
//This is an abomniation
if(responses[i-1].Close > responses[i-2].Close){
bullRunFlag++;
}
if(responses[i-2].Close > responses[i-3].Close){
bullRunFlag++;
}
if(responses[i-3].Close > responses[i-4].Close){
bullRunFlag++;
}
if(responses[i-4].Close > responses[i-5].Close){
bullRunFlag++;
}
if(responses[i-5].Close > responses[i-6].Close){
bullRunFlag++;
}
if(bullRunFlag > 2 && responses[i-1].Close > responses[i-1].Open){//It was a bull run
return true;
}
}
greenCount =0;
}else{
greenCount++;
}
}
return false;
}
public static int GetThreeWhiteSoldiers(List<KlineCandleStickResponse> responses, int curIndex){
if(curIndex < 10){
return 0;
}
KlineCandleStickResponse candle1 = responses[curIndex];
KlineCandleStickResponse candle2 = responses[curIndex-1];
KlineCandleStickResponse candle3 = responses[curIndex-2];
bool isAllGreen = candle1.isGreen() && candle2.isGreen() && candle3.isGreen();
//LP:using average shadow is a bad idea, check each shadow
// float averageShadowRatio = (candle1.getShadowRatio() + candle2.getShadowRatio() + candle3.getShadowRatio())/3f;
bool areSoldiers = AreAllSolid([candle1,candle2, candle3],0.6f);
bool areSoldiersThin = AreAllSolid([candle1,candle2, candle3], 0.4f);
bool areSameSize = AreSameCandleSizes([candle1,candle2,candle3]);
if(isAllGreen && areSoldiers && areSameSize){
//Best
return 3;
}else if(isAllGreen&& areSoldiersThin && areSameSize){
//Not strong
return 2;
}else if(isAllGreen){
//Meh
return 1;
}
return 0;
}
public static int GetThreeBlackCrows(List<KlineCandleStickResponse> responses, int curIndex){
if(curIndex < 10){
return 0;
}
KlineCandleStickResponse candle1 = responses[curIndex];
KlineCandleStickResponse candle2 = responses[curIndex-1];
KlineCandleStickResponse candle3 = responses[curIndex-2];
bool isAllRed = !candle1.isGreen() && !candle2.isGreen() && !candle3.isGreen();
//LP:using average shadow is a bad idea, check each shadow
// float averageShadowRatio = (candle1.getShadowRatio() + candle2.getShadowRatio() + candle3.getShadowRatio())/3f;
bool areSoldiers = AreAllSolid([candle1,candle2, candle3],0.6f);
bool areSoldiersThin = AreAllSolid([candle1,candle2, candle3], 0.4f);
bool areSameSize = AreSameCandleSizes([candle1,candle2,candle3]);
if(isAllRed && areSoldiers && areSameSize){
//Best
return 3;
}else if(isAllRed&& areSoldiersThin && areSameSize){
//Not strong
return 2;
}else if(isAllRed){
//Meh
return 1;
}
return 0;
}
public static bool AreSameCandleSizes(List<KlineCandleStickResponse> responses, float tolerance= 0.5f){
float totalHeight = 0;
foreach(KlineCandleStickResponse response in responses){
totalHeight+= response.getCandleLength();
}
float avgHeight = totalHeight / (float)responses.Count;
foreach(KlineCandleStickResponse response in responses){
float diff = Math.Abs(avgHeight - response.getCandleLength());
if(diff > tolerance){
return false; //One failed to match size
}
}
return true;
}
public static bool AreAllSolid(List<KlineCandleStickResponse> responses, float tolerance= 0.75f){
foreach(KlineCandleStickResponse response in responses){
if(response.getShadowRatio() < tolerance){
return false;
}
}
return true;
}
public static bool isHammer(KlineCandleStickResponse response, float bodyToShadowRatio = 0.3f){
// Check if the candle has a small body compared to total length
float bodyLength = response.getCandleLength();
float totalLength = response.getTotalLength();
// Body should be small compared to total length
if (bodyLength / totalLength > bodyToShadowRatio) {
return false;
}
// Lower shadow should be at least twice the body length
float lowerShadow = (float)Math.Min(response.Open, response.Close) - (float)response.Low;
if (lowerShadow < bodyLength * 2) {
return false;
}
// Upper shadow should be minimal (less than 10% of total length)
float upperShadow = (float)(response.High - Math.Max(response.Open, response.Close));
if (upperShadow > totalLength * 0.1) {
return false;
}
return true;
}
public static bool isInverseHammer(KlineCandleStickResponse response, float bodyToShadowRatio = 0.3f){
// Check if the candle has a small body compared to total length
float bodyLength = response.getCandleLength();
float totalLength = response.getTotalLength();
// Body should be small compared to total length
if (bodyLength / totalLength > bodyToShadowRatio) {
return false;
}
// Upper shadow should be at least twice the body length
float upperShadow = (float)response.High - (float)Math.Max(response.Open, response.Close);
if (upperShadow < bodyLength * 2) {
return false;
}
// Lower shadow should be minimal (less than 10% of total length)
float lowerShadow = (float)Math.Min(response.Open, response.Close) - (float)response.Low;
if (lowerShadow > totalLength * 0.1) {
return false;
}
return true;
}
}