using BinanceExchange.API.Client; using BinanceExchange.API.Enums; using BinanceExchange.API.Models.Request; using BinanceExchange.API.Models.Response; using BinanceExchange.API.Models.WebSocket; using BinanceExchange.API.Websockets; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using static System.Runtime.InteropServices.JavaScript.JSType; namespace SignalsTest { public class CoinWatch { public bool kickstarted = false; public string pair; public int index; public KlineInterval interval = KlineInterval.FifteenMinutes; 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) { this.pair = pair; this.index = index; interval = _interval; usingCache = useCache; Init(); } void Init() { if (usingCache) { if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "/" + pair + ".txt")) { try { } catch { } } } // InitLivestream(); KeepUpdatingCandles(); // TestCallbacks(); } async void TestCallbacks() { while (true) { await Task.Delay(1000); PriceUpdated?.Invoke(this, new BinanceTradeData() { BestAskPrice = 0 }); } } async Task UpdateCandles() { candles = new List(); int rounds = 1; int candleLimit = 150; int intervalInMinutes = Utils.GetMinutesForInterval(interval); if (Utils.GetMinutesForInterval(interval) > 50) { rounds = 10; }else if(Utils.GetMinutesForInterval(interval) > 5){ rounds = 5; } 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(pair); } async void Analyze(string symbol) { int[] mas = new int[] { 7, 12, 25 }; reports = new List(); decimal max = 0; decimal min = 100000000; decimal maxVol = 0; if(candles.Count < 100){return;} for (int i = 0; i < candles.Count; i++) { 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) { min = candles[i].Close; } if (candles[i].Volume > maxVol) { maxVol = candles[i].Volume; } reports.Add(report); } string lineCalSMA = "SMA20"; if(interval!=KlineInterval.FifteenMinutes){ lineCalSMA= "SMA50"; } resistancePoints = Confirmations.GetResistanceLevels(reports,SMA:lineCalSMA); supportPoints = Confirmations.GetSupportiveLevels(reports, SMA:lineCalSMA); for(int i=0; i < reports.Count;i++){ reports[i].isBullFlag = Confirmations.IsBullFlag(reports, i); reports[i].RelativeVolumeIndex = Confirmations.GetRelativeVolumeIndex(reports,i); reports[i].isVwapShort = Patterns.isVwapShort(reports, i); reports[i].isVwapLong = Patterns.isVwapLong(reports,i); } 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; 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; break; } } string triggers = ""; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { triggers += "test"; } // if(isStSwitch){ // triggers += "Switched SuperTrend\n"; // } // if(reports[reports.Count-1].TGOR && !reports[reports.Count-2].TGOR){//Ignore if two in row // triggers += "Price dropped\n"; // } // if (reports[reports.Count - 2].TWS > 1) // { // triggers += $"Three White Soldiers appeared\n"; // } // if (reports[reports.Count - 2].TBC > 1) // { // triggers += $"Three Black Crows appeared\n"; // } // if(reports[reports.Count-2].isHammer){ // triggers+=$"Hammer candle appeared\n"; // } // if(reports[reports.Count-2].isInverseHammer){ // triggers+=$"Inverse Hammer candle appeared\n"; // } // if(reports[reports.Count-2].isBullFlag){ // triggers+=$"Possible Bull Flag\n"; // } if(reports[reports.Count-2].isVwapShort){ triggers+=$"VWAP Short Signal\n"; } if(reports[reports.Count-2].isVwapLong){ triggers+=$"VWAP Long Signal\n"; } if (triggers != "") { List limitedReports = new List(reports); int maxCandlesForChart = 150; if(limitedReports.Count> maxCandlesForChart){ limitedReports.RemoveRange(0,limitedReports.Count-maxCandlesForChart-1); } Picasso.DrawChart(limitedReports, symbol, interval); 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() { int delay = (index * 500); await Task.Delay(delay); UpdateCandles(); while (true) { await Task.Delay(60000 + delay); Console.WriteLine($"Loop call, ({index}) , {DateTime.Now.Minute} = {DateTime.Now.Minute % Utils.GetMinutesForInterval(interval)} "); if (DateTime.Now.Minute % Utils.GetMinutesForInterval(interval) == 0) { UpdateCandles(); } } } void InitLivestream() { var manualWebsocket = new InstanceBinanceWebSocketClient(Brian.Client); var socketId = manualWebsocket.ConnectToIndividualSymbolTickerWebSocket(pair, data => { if (candles.Count > 0) { candles[candles.Count - 1].Close = data.BestAskPrice; } }); } } }