From 77848e3be4070c4dfe8f480f2b71eeff905fdb1a Mon Sep 17 00:00:00 2001 From: Sewmina Date: Thu, 16 Jan 2025 11:27:43 +0530 Subject: [PATCH] Longer time period for logner timeframes, averaged sup and res lines --- Brian.cs | 22 ++++++++ CoinWatch.cs | 138 ++++++++++++++++++++++++++++++++--------------- Confirmations.cs | 12 ++--- Patterns.cs | 4 ++ Picasso.cs | 41 +++++++++----- Utils.cs | 33 +++++++++++- 6 files changed, 188 insertions(+), 62 deletions(-) diff --git a/Brian.cs b/Brian.cs index dd5ecae..48b7471 100644 --- a/Brian.cs +++ b/Brian.cs @@ -56,5 +56,27 @@ namespace SignalsTest return match; } + + public static List GetCombinedResPoints(string symbol){ + List output = new List(); + foreach(CoinWatch watch in watches){ + if(watch.pair == symbol){ + output.AddRange(watch.resistancePoints); + } + } + + return output; + } + + public static List GetCombinedSupPoints(string symbol){ + List output = new List(); + foreach(CoinWatch watch in watches){ + if(watch.pair == symbol){ + output.AddRange(watch.supportPoints); + } + } + + return output; + } } } diff --git a/CoinWatch.cs b/CoinWatch.cs index d254bea..f228215 100644 --- a/CoinWatch.cs +++ b/CoinWatch.cs @@ -22,14 +22,14 @@ namespace SignalsTest public string pair; public int index; public KlineInterval interval = KlineInterval.FifteenMinutes; - public List candles=new List(); + public List candles = new List(); public List reports = new List(); public List resistancePoints = new List(); public List supportPoints = new List(); public event EventHandler PriceUpdated; bool usingCache; - public CoinWatch(string pair,int index, KlineInterval _interval = KlineInterval.FifteenMinutes , bool useCache=false) + public CoinWatch(string pair, int index, KlineInterval _interval = KlineInterval.FifteenMinutes, bool useCache = false) { this.pair = pair; this.index = index; @@ -40,18 +40,23 @@ namespace SignalsTest void Init() { - if(usingCache){ - if(File.Exists(AppDomain.CurrentDomain.BaseDirectory+"/"+pair+".txt")){ - try{ - - }catch{ + if (usingCache) + { + if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "/" + pair + ".txt")) + { + try + { + + } + catch + { } } } // InitLivestream(); KeepUpdatingCandles(); - // TestCallbacks(); + // TestCallbacks(); } async void TestCallbacks() @@ -59,25 +64,56 @@ namespace SignalsTest while (true) { await Task.Delay(1000); - PriceUpdated?.Invoke(this, new BinanceTradeData() { BestAskPrice=0 }); + PriceUpdated?.Invoke(this, new BinanceTradeData() { BestAskPrice = 0 }); } } async Task UpdateCandles() { - GetKlinesCandlesticksRequest req = new GetKlinesCandlesticksRequest(); - req.Interval = interval; - req.Symbol = pair; - req.EndTime = DateTime.Now; - req.Limit = 150; + candles = new List(); - candles = await Brian.Client.GetKlinesCandlesticks(req); - Console.WriteLine($"Done gettings Kandles for {req.Symbol}, {candles.Count} kandles retreived"); + int rounds = 1; + int candleLimit = 150; + int intervalInMinutes = Utils.GetMinutesForInterval(interval); + if (Utils.GetMinutesForInterval(interval) > 50) + { + rounds = 10; + } + + for (int i = 0; i < rounds; i++) + { + DateTime startTime = DateTime.Now.AddMinutes(-intervalInMinutes * candleLimit * (rounds-i)); + DateTime endTime = startTime.AddMinutes(intervalInMinutes * candleLimit); + GetKlinesCandlesticksRequest req = new GetKlinesCandlesticksRequest + { + Interval = interval, + Symbol = pair, + StartTime = startTime, + EndTime = endTime, + Limit = candleLimit + }; + + // Calculate and set the start time for this request + req.StartTime = req.EndTime.Value.AddMinutes(-intervalInMinutes * candleLimit); + + Console.WriteLine($"Fetching kandles for {req.Symbol} (Round {i + 1}/{rounds}): {candles.Count} candles retrieved so far."); + + var response = await Brian.Client.GetKlinesCandlesticks(req); + candles.AddRange(response); + + // Update endTime for the next round + endTime = req.StartTime.Value; + + // Respect the API rate limit + await Task.Delay(1500); + } + Console.WriteLine($"Completed fetching kandles. Total candles retrieved from {candles[0].OpenTime} to {candles[candles.Count-1].OpenTime}"); kickstarted = true; - Analyze(req.Symbol); + Analyze(pair); } - async void Analyze(string symbol){ + async void Analyze(string symbol) + { int[] mas = new int[] { 7, 12, 25 }; reports = new List(); decimal max = 0; @@ -85,44 +121,54 @@ namespace SignalsTest decimal maxVol = 0; - for(int i=0; i < candles.Count; i++){ + for (int i = 0; i < candles.Count; i++) + { - TAReport report = TAReport.Generate(pair, Utils.GetMinutesForInterval(interval) ,candles, i,reports); - if(candles[i].Close > max){ + TAReport report = TAReport.Generate(pair, Utils.GetMinutesForInterval(interval), candles, i, reports); + if (candles[i].Close > max) + { max = candles[i].Close; } - if(candles[i].Close < min){ + if (candles[i].Close < min) + { min = candles[i].Close; } - if(candles[i].Volume > maxVol){ + if (candles[i].Volume > maxVol) + { maxVol = candles[i].Volume; } reports.Add(report); } - - resistancePoints =Confirmations.GetResistanceLevels(reports); - supportPoints = Confirmations.GetSupportiveLevels(reports); + string lineCalSMA = "SMA20"; + if(interval!=KlineInterval.FifteenMinutes){ + lineCalSMA= "SMA50"; + } + resistancePoints = Confirmations.GetResistanceLevels(reports,SMA:lineCalSMA); + supportPoints = Confirmations.GetSupportiveLevels(reports, SMA:lineCalSMA); Console.WriteLine($"Drawing chart for {reports.Count} candles, Coin: {symbol}, ceil:{max}, floor:{min}"); - + // Console.WriteLine("Picasso did his job"); // Console.WriteLine(reports[reports.Count-1].toJson()); - bool isStSwitch=false; + bool isStSwitch = false; - for(int i=0; i< 2; i++){ - bool _isStSwitch = reports[reports.Count-1-i].STUp != reports[reports.Count-i-2].STUp; + for (int i = 0; i < 2; i++) + { + bool _isStSwitch = reports[reports.Count - 1 - i].STUp != reports[reports.Count - i - 2].STUp; - if(_isStSwitch){ - isStSwitch=true; + if (_isStSwitch) + { + isStSwitch = true; break; } } string triggers = ""; - if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)){ - triggers+="test"; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + triggers += "test"; } // if(isStSwitch){ @@ -132,20 +178,27 @@ namespace SignalsTest // triggers += "Price dropped\n"; // } - if(reports[reports.Count-2].TWS > 1){ + if (reports[reports.Count - 2].TWS > 1) + { triggers += $"Three White Soldiers appeared"; } - if(reports[reports.Count-2].TBC > 1){ + if (reports[reports.Count - 2].TBC > 1) + { triggers += $"Three Black Crows appeared"; } - if(triggers!= ""){ - Picasso.DrawChart(reports, max ,min, maxVol, symbol, interval); + if (triggers != "") + { + List limitedReports = new List(reports); + if(limitedReports.Count> 200){ + limitedReports.RemoveRange(0,limitedReports.Count-150); + } + Picasso.DrawChart(limitedReports, symbol, interval); - string message = $"`{symbol}` [{Utils.GetMinutesForInterval(interval)}m] {triggers} \nCurrent price: {reports[reports.Count-1].Close}"; + string message = $"`{symbol}` [{Utils.GetMinutesForInterval(interval)}m] {triggers} \nCurrent price: {reports[reports.Count - 1].Close}"; Messenger.instance.ScheduleMessage(message, symbol, Utils.GetMinutesForInterval(interval).ToString()); } - + } async void KeepUpdatingCandles() @@ -154,7 +207,7 @@ namespace SignalsTest await Task.Delay(delay); UpdateCandles(); - while(true) + while (true) { await Task.Delay(60000 + delay); Console.WriteLine($"Loop call, ({index}) , {DateTime.Now.Minute} = {DateTime.Now.Minute % Utils.GetMinutesForInterval(interval)} "); @@ -167,7 +220,8 @@ namespace SignalsTest var manualWebsocket = new InstanceBinanceWebSocketClient(Brian.Client); var socketId = manualWebsocket.ConnectToIndividualSymbolTickerWebSocket(pair, data => { - if(candles.Count > 0){ + if (candles.Count > 0) + { candles[candles.Count - 1].Close = data.BestAskPrice; } }); diff --git a/Confirmations.cs b/Confirmations.cs index 3d5a32c..d1a8ebf 100644 --- a/Confirmations.cs +++ b/Confirmations.cs @@ -58,7 +58,7 @@ public static class Confirmations return HeightIncrement; } - public static List GetSupportiveLevels(List reports, float tolerance = 0.1f, int steps = 5){ + public static List GetSupportiveLevels(List reports, float tolerance = 0.1f, int steps = 5, string SMA="SMA20"){ List allSups = new List(); decimal highest = 0; @@ -76,8 +76,8 @@ public static class Confirmations if(k reports[k].candle.High; - bool MATopBefore = reports[k-1].SMA20 > reports[k-1].candle.High; + bool MATopNow = decimal.Parse(Utils.GetPropByName(reports[k], SMA).ToString() ?? "0") > reports[k].candle.High; + bool MATopBefore = decimal.Parse(Utils.GetPropByName(reports[k-1], SMA).ToString() ?? "0") > reports[k-1].candle.High; bool MACrossed = MATopBefore!=MATopNow; if(!MACrossed){continue;}//No cross @@ -108,7 +108,7 @@ public static class Confirmations return formattedSups; } - public static List GetResistanceLevels(List reports, float tolerance = 0.1f, int steps = 5){ + public static List GetResistanceLevels(List reports, float tolerance = 0.1f, int steps = 5, string SMA="SMA20"){ List allResistances = new List(); decimal highest = 0; @@ -126,8 +126,8 @@ public static class Confirmations if(k reports[k].candle.High; - bool MATopBefore = reports[k-1].SMA20 > reports[k-1].candle.High; + bool MATopNow = decimal.Parse(Utils.GetPropByName(reports[k], SMA).ToString() ?? "0") > reports[k].candle.High; + bool MATopBefore = decimal.Parse(Utils.GetPropByName(reports[k-1], SMA).ToString() ?? "0") > reports[k-1].candle.High; bool MACrossed = MATopBefore!=MATopNow; if(!MACrossed){continue;}//No cross diff --git a/Patterns.cs b/Patterns.cs index a5e4963..cf6b54a 100644 --- a/Patterns.cs +++ b/Patterns.cs @@ -148,4 +148,8 @@ public static class Patterns{ return true; } + + // public static bool isHammer(KlineCandleStickResponse response, float ratioThreshold = 0.3f){ + + // } } \ No newline at end of file diff --git a/Picasso.cs b/Picasso.cs index 838ae56..7f8320a 100644 --- a/Picasso.cs +++ b/Picasso.cs @@ -14,9 +14,27 @@ public class Picasso{ - public static void DrawChart(List reports, decimal max, decimal min, decimal volMax, string filename="test", KlineInterval interval = KlineInterval.FifteenMinutes){ + public static void DrawChart(List reports, string filename="test", KlineInterval interval = KlineInterval.FifteenMinutes){ // float height = (float)Math.Ceiling(max - min) * 2f; // float width = ((float)height / 9f) * 16f; + decimal max = 0; + decimal min = 10000000000000; + decimal volMax =0; + + foreach(TAReport report in reports){ + if(max < report.High){ + max = report.High; + } + + if(min > report.Low){ + min = report.Low; + } + + if(volMax < report.candle.Volume){ + volMax = report.candle.Volume; + } + } + decimal heightRange = max-min; float height=1080; float width = 1920; @@ -127,15 +145,19 @@ public class Picasso{ #region LINES - CoinWatch longestWatch = Brian.GetCoinWatchLongest(filename); + List allResPoints = Brian.GetCombinedResPoints(filename); + List allSupPoints = Brian.GetCombinedSupPoints(filename); - foreach(decimal point in longestWatch.resistancePoints){ + List processedResPoints = Utils.GetAveragePoints(allResPoints, min,max); + List processedSupPoints = Utils.GetAveragePoints(allSupPoints,min,max); + + foreach(decimal point in processedResPoints){ float yVal = ((float)(point-min) * heightMultiplier) + candlesOffset; // Console.WriteLine($"{filename} res at {yVal/height}"); img.Mutate(ctx=> ctx.DrawLine(Color.Red,1f, [new PointF(0, yVal), new PointF(width, yVal)])); } - foreach(decimal point in longestWatch.supportPoints){ + foreach(decimal point in processedSupPoints){ float yVal = ((float)(point-min) * heightMultiplier) + candlesOffset; // Console.WriteLine($"{filename} sup at {yVal/height}"); img.Mutate(ctx=> ctx.DrawLine(Color.Green,1f, [new PointF(0, yVal), new PointF(width, yVal)])); @@ -182,10 +204,10 @@ public class Picasso{ PathBuilder builder = new PathBuilder(); builder.SetOrigin(new PointF(0,0)); for(int i=0; i < reports.Count; i++){ - float newVal = float.Parse(GetPropByName(reports[i],propName).ToString() ?? "0"); + float newVal = float.Parse(Utils.GetPropByName(reports[i],propName).ToString() ?? "0"); // Console.WriteLine( newVal); - float prevVal = i > 0 ? float.Parse(GetPropByName(reports[i-1],propName).ToString() ?? "0") : 0; + float prevVal = i > 0 ? float.Parse(Utils.GetPropByName(reports[i-1],propName).ToString() ?? "0") : 0; // Console.WriteLine( prevVal); float preValY =( prevVal - min) * heightMultiplier ; float newValY=(newVal - min) * heightMultiplier; @@ -198,12 +220,7 @@ public class Picasso{ return builder.Build(); } - static object GetPropByName(TAReport report, string propName){ - string json = report.toJson(); - Dictionary dic = JsonConvert.DeserializeObject>(json) ?? new Dictionary(); - // Console.WriteLine(dic[propName]); - return dic[propName]; - } + #endregion } \ No newline at end of file diff --git a/Utils.cs b/Utils.cs index 024cf30..901e19f 100644 --- a/Utils.cs +++ b/Utils.cs @@ -1,6 +1,7 @@ using BinanceExchange.API.Enums; using BinanceExchange.API.Models.Response; using BinanceExchange.API.Models.WebSocket; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; @@ -12,7 +13,7 @@ namespace SignalsTest public class Utils { public static int GetMinutesForInterval(KlineInterval interval) - + { switch (interval) { @@ -62,6 +63,34 @@ namespace SignalsTest return response; } - + public static object GetPropByName(TAReport report, string propName) + { + string json = report.toJson(); + Dictionary dic = JsonConvert.DeserializeObject>(json) ?? new Dictionary(); + // Console.WriteLine(dic[propName]); + return dic[propName]; + } + + public static List GetAveragePoints(List input, decimal min, decimal max){ + List processed = new List(); + List ignoredPoints = new List(); + for(int x=0; x < input.Count; x++){ + if(ignoredPoints.Contains(input[x])){continue;}//Already processed + decimal avg = input[x]; + for(int y=0; y < input.Count; y++){ + decimal point = input[y]; + decimal diff = Math.Abs(avg-point) / (max-min); + if(diff < (decimal)0.05){ + avg+=point; + avg/=2; + ignoredPoints.Add(input[y]); + } + } + + processed.Add(avg); + } + + return processed; + } } }