From a2c307b3d881900c9ca33b1ef9ec2a5e85793a79 Mon Sep 17 00:00:00 2001 From: kyh <1329522@naver.com> Date: Tue, 27 May 2025 11:40:01 +0900 Subject: [PATCH] =?UTF-8?q?buy,=20sell=20=EC=A0=95=EA=B7=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IndicatorProcess.cs | 2 +- .../SMABandConditionSetup.cs | 183 ++++++++++++------ 2 files changed, 125 insertions(+), 60 deletions(-) diff --git a/BitgetApi/IndicatorConditionSetup/IndicatorProcess.cs b/BitgetApi/IndicatorConditionSetup/IndicatorProcess.cs index 0d921f5..468c790 100644 --- a/BitgetApi/IndicatorConditionSetup/IndicatorProcess.cs +++ b/BitgetApi/IndicatorConditionSetup/IndicatorProcess.cs @@ -440,7 +440,7 @@ namespace BitgetAPI.IndicatorConditionSetup { var buyItem = UpBuyList[market]; - var flag = (bool)buyItem["Flag"]; + //var flag = (bool)buyItem["Flag"]; if (interval < MCandleTimeType.H1) { var buyTime = ((DateTime)buyItem["BuyDate"]).AddMinutes(5); diff --git a/BitgetApi/IndicatorConditionSetup/SMABandConditionSetup.cs b/BitgetApi/IndicatorConditionSetup/SMABandConditionSetup.cs index d2d95e2..e494604 100644 --- a/BitgetApi/IndicatorConditionSetup/SMABandConditionSetup.cs +++ b/BitgetApi/IndicatorConditionSetup/SMABandConditionSetup.cs @@ -12,99 +12,164 @@ namespace BitgetApi.IndicatorConditionSetup public class SMABandConditionSetup { private readonly int rangeLookback = 12; - private readonly double rangeThresholdPercent = 0.7; - private readonly int bandLength = 12; - private readonly int recentTouchLookbackTypeLong = 5; - private readonly int recentTouchLookbackTypeShort = 15; - private int? sma4LongTouchBar = null; - private int? sma4ShortTouchBar = null; + private readonly double rangeThresholdPercent = 0.4; + private readonly int recentTouchLookback = 5; + private readonly int recentTouch2Lookback = 15; + public bool Calculate(List candles, SMABandType type) - { - var currentIndex = candles.Count - 1; + { var close = candles.Select(t => t.Close).ToList(); + close.RemoveAt(close.Count - 1); + var high = candles.Select(t=>t.High).ToList(); + high.RemoveAt(high.Count - 1); + var low = candles.Select(t => t.Low).ToList(); + low.RemoveAt(low.Count - 1); - if (currentIndex < 72 || close.Count <= currentIndex || high.Count <= currentIndex || low.Count <= currentIndex) - return false; + var open = candles.Select(t => t.Open).ToList(); + open.RemoveAt(open.Count - 1); - // === SMA(4) 계산 === - double sma4 = close.GetRange(currentIndex - 3, 4).Average(); - double prevSma4 = new[] { close[currentIndex - 4], close[currentIndex - 1], close[currentIndex - 2], close[currentIndex - 3] }.Average(); - double prev2Sma4 = new[] { close[currentIndex - 4], close[currentIndex - 5], close[currentIndex - 2], close[currentIndex - 3] }.Average(); + int i = close.Count - 1; // 최신 데이터 기준 - // === SMA(4) 밴드 계산 === - List sma4Series = new List(); - for (int i = currentIndex - bandLength + 1; i <= currentIndex; i++) - { - var s = close.GetRange(i - 3, 4).Average(); - sma4Series.Add(s); - } - double sma4High = sma4Series.Max(); - double sma4Low = sma4Series.Min(); - double sma4Middle = sma4Series.Average(); + double sma4 = Avg(close[i], close[i - 1], close[i - 2], close[i - 3]); + double prevSma4 = Avg(close[i - 4], close[i - 1], close[i - 2], close[i - 3]); + double prev2Sma4 = Avg(close[i - 4], close[i - 5], close[i - 2], close[i - 3]); + double prev3Sma4 = Avg(close[i - 4], close[i - 5], close[i - 6], close[i - 3]); - // 이전 SMA4 밴드 - List prevSma4Series = new List(); - for (int i = currentIndex - bandLength + 1; i <= currentIndex; i++) - { - var s = new[] { close[i - 4], close[i - 1], close[i - 2], close[i - 3] }.Average(); - prevSma4Series.Add(s); - } - double prevSma4High = prevSma4Series.Max(); - double prevSma4Low = prevSma4Series.Min(); - double prevSma4Middle = prevSma4Series.Average(); + double sma4High = Highest(close, i, 12, useSma4: true); + double sma4Middle = SMA(close, i, 12, useSma4: true); + double sma4Low = Lowest(close, i, 12, useSma4: true); - List prev2Sma4Series = new List(); - for (int i = currentIndex - bandLength + 1; i <= currentIndex; i++) - { - var s = new[] { close[i - 4], close[i - 5], close[i - 2], close[i - 3] }.Average(); - prev2Sma4Series.Add(s); - } - double prev2Sma4Middle = prev2Sma4Series.Average(); - double prev2Sma4High = prev2Sma4Series.Max(); - double prev2Sma4Low = prev2Sma4Series.Min(); + double prevSma4High = Highest(close, i - 1, 12, useSma4: true); + double prevSma4Middle = SMA(close, i - 1, 12, useSma4: true); + double prevSma4Low = Lowest(close, i - 1, 12, useSma4: true); + double prev2Sma4High = Highest(close, i - 2, 12, useSma4: true); + double prev2Sma4Middle = SMA(close, i - 2, 12, useSma4: true); + double prev2Sma4Low = Lowest(close, i - 2, 12, useSma4: true); - // === 횡보 구간 === - double highestHigh = high.Skip(currentIndex - rangeLookback + 1).Take(rangeLookback).Max(); - double lowestLow = low.Skip(currentIndex - rangeLookback + 1).Take(rangeLookback).Min(); + double highestHigh = high.Skip(i - rangeLookback).Take(rangeLookback).Max(); + double lowestLow = low.Skip(i - rangeLookback).Take(rangeLookback).Min(); double priceRange = highestHigh - lowestLow; bool isSideways = priceRange > (highestHigh * rangeThresholdPercent / 100.0); - // === 최근 터치 === - if (sma4 == sma4Low) - sma4LongTouchBar = currentIndex; + bool isLongRecentTouch = false; + for (int j = i - recentTouchLookback + 1; j <= i; j++) + { + double sma4_j = Avg(close[j], close[j - 1], close[j - 2], close[j - 3]); + double sma4Low_j = Lowest(close, j, 12, useSma4: true); + double prevSma4_j = Avg(close[j - 4], close[j - 1], close[j - 2], close[j - 3]); + double prevSma4Low_j = Lowest(close, j - 1, 12, useSma4: true); + if (sma4_j >= sma4Low_j && prevSma4_j == prevSma4Low_j) + { + isLongRecentTouch = true; + break; + } + } - bool isLongRecentTouch = sma4LongTouchBar.HasValue && currentIndex - sma4LongTouchBar.Value >= recentTouchLookbackTypeLong; + bool isShortRecentTouch = false; + for (int j = i - recentTouchLookback + 1; j <= i; j++) + { + double sma4_j = Avg(close[j], close[j - 1], close[j - 2], close[j - 3]); + double sma4High_j = Highest(close, j, 12, useSma4: true); + double prevSma4_j = Avg(close[j - 4], close[j - 1], close[j - 2], close[j - 3]); + double prevSma4High_j = Highest(close, j - 1, 12, useSma4: true); + if (sma4_j <= sma4High_j && prevSma4_j == prevSma4High_j) + { + isShortRecentTouch = true; + break; + } + } - if (sma4 < sma4Middle) - sma4ShortTouchBar = currentIndex; + bool isShort2RecentTouch = false; + for (int j = i - recentTouch2Lookback + 1; j <= i; j++) + { + double sma4_j = Avg(close[j], close[j - 1], close[j - 2], close[j - 3]); + double sma4Middle_j = SMA(close, j, 12, useSma4: true); + if (sma4_j > sma4Middle_j) + { + isShort2RecentTouch = true; + break; + } + } - bool isShortRecentTouch = sma4ShortTouchBar.HasValue && currentIndex - sma4ShortTouchBar.Value >= recentTouchLookbackTypeShort; + bool isLong2RecentTouch = false; + for (int j = i - recentTouch2Lookback + 1; j <= i; j++) + { + double sma4_j = Avg(close[j], close[j - 1], close[j - 2], close[j - 3]); + double sma4Middle_j = SMA(close, j, 12, useSma4: true); + if (sma4_j > sma4Middle_j) + { + isShort2RecentTouch = true; + break; + } + } + + bool rawNewLong = (isSideways && ! isLongRecentTouch && isLong2RecentTouch && sma4 == sma4High && prevSma4 (prevSma4Middle - prev2Sma4Middle))) || + (isSideways && isLong2RecentTouch && sma4 == sma4High && prevSma4 == prevSma4High && prevSma4 < sma4 && ((sma4Middle - prevSma4Middle) > (prevSma4Middle - prev2Sma4Middle))); + bool rawLongSell = prevSma4High == prevSma4 && sma4High > sma4; + + bool rawNewShort = (!isShortRecentTouch && isShort2RecentTouch && sma4 == sma4Low && prevSma4 > sma4 && prevSma4 > prevSma4Low && ((sma4Middle - prevSma4Middle) < (prevSma4Middle - prev2Sma4Middle))) || + (isShort2RecentTouch && sma4 == sma4Low && prevSma4 == prevSma4Low && prevSma4 > sma4 && ((sma4Middle - prevSma4Middle) < (prevSma4Middle - prev2Sma4Middle))); + bool rawShortSell = open[open.Count - 1] > sma4Middle || (sma4High == sma4 && prevSma4High > prevSma4) ||(prev2Sma4Low == prev2Sma4 && prevSma4Low < prevSma4); ; // === 시그널 계산 === if (type == SMABandType.LongBuy) { - return isLongRecentTouch && isSideways && prevSma4 < sma4 && sma4High == sma4 && - prevSma4High > prevSma4 && (prev2Sma4Middle - prevSma4Middle) > (prevSma4Middle - sma4Middle); + return rawNewLong; } else if (type == SMABandType.ShortBuy) { - return isShortRecentTouch && prevSma4High > prevSma4 && prev2Sma4High == prev2Sma4 && - prevSma4 > sma4; + return rawNewShort; } + else if (type == SMABandType.LongSell) { - return (!isSideways && prevSma4High > prevSma4) || (isSideways && prev2Sma4High > prev2Sma4 && prevSma4High > prevSma4); + return rawLongSell; } else if (type == SMABandType.ShortSell) { - return (sma4High == sma4 && prevSma4High > prevSma4) || (!isSideways && prevSma4Low == prevSma4 && sma4Low < sma4) || (isSideways && prev2Sma4Low == prev2Sma4 && prevSma4Low < prevSma4 && sma4Low < sma4); + return rawShortSell; } return false; } + + private double Avg(params double[] values) => values.Average(); + + private double SMA(List source, int currentIndex, int period, bool useSma4) + { + var values = new List(); + for (int i = currentIndex - period + 1; i <= currentIndex; i++) + { + double sma4 = Avg(source[i], source[i - 1], source[i - 2], source[i - 3]); + values.Add(sma4); + } + return values.Average(); + } + + private double Highest(List source, int currentIndex, int period, bool useSma4) + { + var values = new List(); + for (int i = currentIndex - period + 1; i <= currentIndex; i++) + { + double sma4 = Avg(source[i], source[i - 1], source[i - 2], source[i - 3]); + values.Add(sma4); + } + return values.Max(); + } + + private double Lowest(List source, int currentIndex, int period, bool useSma4) + { + var values = new List(); + for (int i = currentIndex - period + 1; i <= currentIndex; i++) + { + double sma4 = Avg(source[i], source[i - 1], source[i - 2], source[i - 3]); + values.Add(sma4); + } + return values.Min(); + } } }