using System.Diagnostics; using BinanceExchange.API.Models.Response; public static class Indicators { public static decimal getSMA(List responses, int curIndex, int interval, int startIndex = 0) { // curIndex = Math.Clamp(curIndex,0, responses.Count); // decimal total = 0; // for(int i=curIndex-interval; i < curIndex; i++){ // total += responses[i].Close; // } // // decimal length = (curIndex-startIndex); if(length <= 0){length=1;} // // decimal N = (length / (decimal)interval); // Console.WriteLine($"SMA Cacl ({interval}) : {total}/{interval} = {total/interval}"); // return total / interval; decimal total = 0; for (int x = (curIndex > 1500) ? 1500 : 0; x < interval; x++) { total += (curIndex - x >= 0) ? responses[curIndex - x].Close : (decimal)0; } return total / (decimal)interval; } public static decimal getSMA(List responses, int curIndex, int interval, int startIndex = 0) { decimal total = 0; for (int x = (curIndex > 1500) ? 1500 : 0; x < interval; x++) { total += (curIndex - x >= 0) ? responses[curIndex - x] : (decimal)0; } return total / (decimal)interval; } public static decimal getEMA(List responses, int curIndex, int startIndex, int periods, decimal? prevEma = null) { if (curIndex < 1) { return 0; } if (startIndex - curIndex > 1500) { return 0; }; if (curIndex >= responses.Count) { return 0; }; // decimal N = (decimal)curIndex / (decimal)periods; decimal multiplier = (decimal)2 / ((decimal)(periods + 1)); decimal firstHalf = responses[curIndex].Close * multiplier; //First half of the equation decimal secondHalf = getEMA(responses, curIndex - 1, startIndex, periods) * (1 - multiplier); //Second half of the equation // decimal secondHalf = (prevEma ?? getSMA(responses, curIndex-1, periods)) * (1- multiplier); //Second half of the equation return firstHalf + secondHalf; } public static decimal getEMA(List responses, int curIndex, int startIndex, int periods) { if (curIndex < 1) { return 0; } if (startIndex - curIndex > 1500) { return 0; }; if (curIndex >= responses.Count) { return 0; }; // decimal N = (decimal)curIndex / (decimal)periods; decimal multiplier = (decimal)2 / ((decimal)(periods + 1)); decimal firstHalf = responses[curIndex] * multiplier; //First half of the equation decimal secondHalf = getEMA(responses, curIndex - 1, startIndex, periods) * (1 - multiplier); //Second half of the equation // decimal secondHalf = (prevEma ?? getSMA(responses, curIndex-1, periods)) * (1- multiplier); //Second half of the equation return firstHalf + secondHalf; } public static decimal getMACD(List responses, int shortPeriod, int longPeriod, int curIndex) { return getEMA(responses, curIndex, curIndex, shortPeriod) - getEMA(responses, curIndex, curIndex, longPeriod); } public static decimal getATR(List responses, int period, int curIndex, List prevATRs) { if (curIndex <= 0 || curIndex > responses.Count) { return 0; } if (curIndex >= responses.Count) { return 0; }; decimal TR = responses[curIndex].High - responses[curIndex].Low; if (curIndex > 1) { decimal tr2 = responses[curIndex].High - responses[curIndex - 1].Close; decimal tr3 = responses[curIndex].Low - responses[curIndex - 1].Close; if (tr2 > TR) { TR = tr2; } if (tr3 > TR) { TR = tr3; } } if (curIndex < period) { //get just the TR return TR; } decimal prevATR = 0; if (prevATRs.Count > 0) { // int start = curIndex - period; // for (int i = start; i < curIndex; i++) // { // prevATR += prevATRs[i]; // } // prevATR = (prevATR) / (decimal)(curIndex-start); prevATR = prevATRs[curIndex - 1]; } decimal ATR = (decimal)((prevATR * (decimal)(period - 1)) + TR) / (decimal)period; return ATR; } public static decimal getVwapWeekly(List responses, int index){ if(index < 15){return 0;} decimal cumPrice = 0; decimal cumVolume = 0; for(int i=index; i > 0; i--){ decimal typicalPrice = (responses[i].High + responses[i].Low + responses[i].Close) / 3; cumPrice += typicalPrice * responses[i].Volume; cumVolume += responses[i].Volume; if(responses[i].CloseTime.DayOfWeek == DayOfWeek.Sunday && responses[i].CloseTime.Hour == 23 && responses[i].CloseTime.Minute == 59){ break; } } return cumPrice/ cumVolume; } public static decimal getVwapMonthly(List responses, int index){ if(index < 15){return 0;} decimal cumPrice = 0; decimal cumVolume = 0; for(int i=index; i > 0; i--){ decimal typicalPrice = (responses[i].High + responses[i].Low + responses[i].Close) / 3; cumPrice += typicalPrice * responses[i].Volume; cumVolume += responses[i].Volume; if(responses[i].CloseTime.Date.Day == 1 && responses[i].OpenTime.Hour == 0 && responses[i].OpenTime.Minute == 0){ break; } } return cumPrice/ cumVolume; } public static decimal getRSI(List responses, int index, int period = 14) { decimal avgGain = 0; decimal avgLoss = 0; if (index < period) { return 0; } for (int i = index; i > index - period; i--) { decimal change = responses[i].Close - responses[i - 1].Close; if (change > 0) { avgGain += change; } else { avgLoss += Math.Abs(change); } } avgGain /= period; avgLoss /= period; if (avgLoss == 0) { return 100; // If there's no loss, RSI is 100 } decimal rs = avgGain / avgLoss; decimal rsi = 100 - (100 / (1 + rs)); return rsi; } public static bool didMACDLineCrossSignalLine(decimal[] MACDs, decimal[] Signals, int index, int period = 7, decimal threshold = (decimal)0.1) { int counter = 0; if (index >= MACDs.Length || index >= Signals.Length) { return false; } if (index - period < 0) { return false; }; for (int i = index; i > index - period; i--) { if (MACDs[i] < Signals[i]) { counter++; } } bool wasMACDUnder = counter > ((float)period / 2f); return wasMACDUnder && MACDs[index] > Signals[index]; } public static decimal getAvgDiff(List responses, int i) { decimal avgDiff = 0; if (i > 10) { for (int k = 1; k < 6; k++) { avgDiff += responses[i - k].Close; } avgDiff = avgDiff / (decimal)5; avgDiff = responses[i].Close - avgDiff; } return avgDiff; } public static decimal getStochastic(List responses, int i, int length = 14){ if(i < 20){ return 0; } decimal highest = 0; decimal lowest = 1000000000000000; for(int k =0; k < length; k++){ if(responses[i-k].Low < lowest){ lowest = responses[i-k].Low; } if(responses[i-k].High > highest){ highest = responses[i-k].High; } } decimal topHalf = responses[i].Close - lowest; decimal botHalf = highest - lowest; return (topHalf /botHalf) * 100; } public static decimal getStochasticMA(List responses, int i, int length = 14, int period = 3){ decimal total = 0; for(int k =0; k < period; k++){ total += getStochastic(responses, i-k); } return total / period; } }