using DevExpress.XtraEditors.TextEditController.InputHandler; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolTip; namespace BitgetApi.IndicatorConditionSetup { public class TradingViewConditionSetup { // 기본 파라미터 public int LengthMA = 34; public int LengthSignal = 12; public int AdxLength = 12; public double AdxThreshold = 24; public double RangeThreshold = 1; public double RangeThresholdSell = 1; // 데이터 입력: High, Low, Close 배열 (최근 것이 맨 끝) public List High; public List Low; public List Close; // SMA4 계산용 private double[] Sma4; public void SetData(List high, List low, List close) { High = high; Low = low; Close = close; Sma4 = ComputeSma4(); } // 1. SMMA 계산 private double CalcSmma(List src, int len) { double smma = src.Take(len).Average(); for (int i = len; i < src.Count; i++) { smma = (smma * (len - 1) + src[i]) / len; } return smma; } // 2. ZLEMA 계산 private double CalcZlema(List src, int length) { double ema1 = Ema(src, length); double ema2 = Ema(Enumerable.Repeat(ema1, src.Count).ToList(), length); double d = ema1 - ema2; return ema1 + d; } // 3. EMA 계산 private double Ema(List src, int length) { double alpha = 2.0 / (length + 1); double ema = src[0]; for (int i = 1; i < src.Count; i++) { ema = alpha * src[i] + (1 - alpha) * ema; } return ema; } // 4. SMA(4) 계산 private double[] ComputeSma4() { double[] sma4 = new double[Close.Count]; for (int i = 3; i < Close.Count; i++) { sma4[i] = (Close[i] + Close[i - 1] + Close[i - 2] + Close[i - 3]) / 4.0; } return sma4; } // 5. ADX (가장 간단한 형태) private double ComputeAdx() { // 간단화: 실제 구현 시 true range, directional movement 등 추가 필요 return 25.0; // 더미값 또는 타 라이브러리 사용 가능 } // 6. Impulse MACD 계산 public double ComputeMd(bool flag = true) { if (flag) { double hi = CalcSmma(High, LengthMA); double lo = CalcSmma(Low, LengthMA); var hlc3 = High.Zip(Low, (h, l) => (h + l + Close.Last()) / 3).ToList(); double mi = CalcZlema(hlc3, LengthMA); if (mi > hi) return mi - hi; else if (mi < lo) return mi - lo; return 0; } else { var highTemp = new List(); foreach(var item in High) highTemp.Add(item); var lowTemp = new List(); foreach (var item in Low) lowTemp.Add(item); var closeTemp = new List(); foreach (var item in Close) closeTemp.Add(item); highTemp.RemoveAt(highTemp.Count - 1); lowTemp.RemoveAt(lowTemp.Count - 1); closeTemp.RemoveAt(closeTemp.Count - 1); double hi = CalcSmma(highTemp, LengthMA); double lo = CalcSmma(lowTemp, LengthMA); var hlc3 = highTemp.Zip(lowTemp, (h, l) => (h + l + closeTemp.Last()) / 3).ToList(); double mi = CalcZlema(hlc3, LengthMA); if (mi > hi) return mi - hi; else if (mi < lo) return mi - lo; return 0; } } // 7. MACD, SignalLine 계산 public (double macdLine, double signalLine) ComputeMacd() { double macdLine = Ema(Close, 34) - Ema(Close, 12); double signalLine = Ema(Enumerable.Repeat(macdLine, Close.Count).ToList(), 12); return (macdLine, signalLine); } // 7. MACD, SignalLine 계산(이전꺼) public (double macdLine, double signalLine) PrevComputeMacd() { var temp = new List(); foreach (var item in Close) temp.Add(item); temp.RemoveAt(temp.Count - 1); double macdLine = Ema(temp, 34) - Ema(temp, 12); double signalLine = Ema(Enumerable.Repeat(macdLine, temp.Count).ToList(), 12); return (macdLine, signalLine); } // 8. RangeBound 필터 public bool IsRangeBound() { double highestHigh = High.Skip(High.Count - 12).Max(); double lowestLow = Low.Skip(Low.Count - 12).Min(); double range = highestHigh - lowestLow; return range < (highestHigh * RangeThreshold / 100.0); } public bool IsRangeBoundSell() { double highestHigh = High.Skip(High.Count - 12).Max(); double lowestLow = Low.Skip(Low.Count - 12).Min(); double range = highestHigh - lowestLow; return range < (highestHigh * RangeThresholdSell / 100.0); } // 9. 트렌드 여부 public bool IsTrending() { return ComputeAdx() > AdxThreshold; } public double GetAvgData(int range) { var sma = 0.0; for (var i = 0; i < range; i++) { sma += Close[Close.Count - (i + 1)]; } return sma / range; } public double GetAvgData(int range, int prev) { var sma = 0.0; for (var i = 0; i < range; i++) { sma += Close[Close.Count - (i + 1 + prev)]; } return sma / range; } // 10. 매수 조건 public bool IsLongSignal() { double md = ComputeMd(); double prevMd = ComputeMd(false); var (macd, signal) = ComputeMacd(); var (prevMacd, prevSignal) = PrevComputeMacd(); bool isUptrend = Close.Last() > Sma4.Last(); return ((prevMd == 0 && md > 0) || (prevMacd < prevSignal && macd > prevMacd && macd > signal && md > 0)) && IsTrending() && IsSmaMiddle(4, 12, true, GetAvgData(72)) && GetAvgData(4) > GetAvgData(4, 1); //return isUptrend && // ((prevMd == 0 && md > 0) || (macd > prevMacd && signal > prevSignal && md > 0 && macd > signal)) && // IsTrending() && !IsRangeBound(); } // 11. 매도 조건 public bool IsShortSignal() { double md = ComputeMd(); double prevMd = ComputeMd(false); var (macd, signal) = ComputeMacd(); var (prevMacd, prevSignal) = PrevComputeMacd(); bool isDowntrend = Close.Last() < Sma4.Last(); return ((prevMd == 0 && md < 0) || (prevMacd > prevSignal && macd < prevMacd && macd < signal && md < 0)) && IsTrending() && IsSmaMiddle(4, 12, false, GetAvgData(72)) && GetAvgData(4) < GetAvgData(4, 1); //return isDowntrend && // ((prevMd == 0 && md < 0) || (macd < prevMacd && signal < prevSignal && md < 0 && macd < signal)) && // IsTrending() && !IsRangeBoundSell(); } public bool IsSmaHigh(int range, int count) { var list = new List(); for (int i = Close.Count - count - 1; i < count; i++) { var sum = 0.0; for(int j = 0;j < range; j++) { sum += Close[i-j]; } var data = sum / range; list.Add(data); } if (list.Max() == list[list.Count - 1]) return true; else return false; } public bool IsSmaLow(int range, int count) { var list = new List(); for (int i = Close.Count - count - 1; i < count; i++) { var sum = 0.0; for (int j = 0; j < range; j++) { sum += Close[i - j]; } var data = sum / range; list.Add(data); } if (list.Min() == list[list.Count - 1]) return true; else return false; } public bool IsSmaMiddle(int range, int count, bool longFlag, double value) { var list = new List(); for (int i = Close.Count - count - 1; i < count; i++) { var sum = 0.0; for (int j = 0; j < range; j++) { sum += Close[i - j]; } var data = sum / range; list.Add(data); } if (longFlag) { if(value < list.Average()) { return true; } } else { if (value > list.Average()) { return true; } } return false; } } }