252 lines
8.3 KiB
C#
252 lines
8.3 KiB
C#
using System.Diagnostics;
|
|
using BinanceExchange.API.Models.Response;
|
|
|
|
public static class Indicators
|
|
{
|
|
|
|
public static decimal getSMA(List<KlineCandleStickResponse> 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<decimal> 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<KlineCandleStickResponse> 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<decimal> 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<KlineCandleStickResponse> responses, int shortPeriod, int longPeriod, int curIndex)
|
|
{
|
|
return getEMA(responses, curIndex, curIndex, shortPeriod) - getEMA(responses, curIndex, curIndex, longPeriod);
|
|
}
|
|
|
|
public static decimal getATR(List<KlineCandleStickResponse> responses, int period, int curIndex, List<decimal> 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<KlineCandleStickResponse> 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<KlineCandleStickResponse> 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<KlineCandleStickResponse> 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<KlineCandleStickResponse> 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<KlineCandleStickResponse> 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<KlineCandleStickResponse> 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;
|
|
}
|
|
} |