Longer time period for logner timeframes, averaged sup and res lines

This commit is contained in:
Sewmina 2025-01-16 11:27:43 +05:30
parent bf83a4b912
commit 77848e3be4
6 changed files with 188 additions and 62 deletions

View File

@ -56,5 +56,27 @@ namespace SignalsTest
return match; return match;
} }
public static List<decimal> GetCombinedResPoints(string symbol){
List<decimal> output = new List<decimal>();
foreach(CoinWatch watch in watches){
if(watch.pair == symbol){
output.AddRange(watch.resistancePoints);
}
}
return output;
}
public static List<decimal> GetCombinedSupPoints(string symbol){
List<decimal> output = new List<decimal>();
foreach(CoinWatch watch in watches){
if(watch.pair == symbol){
output.AddRange(watch.supportPoints);
}
}
return output;
}
} }
} }

View File

@ -22,14 +22,14 @@ namespace SignalsTest
public string pair; public string pair;
public int index; public int index;
public KlineInterval interval = KlineInterval.FifteenMinutes; public KlineInterval interval = KlineInterval.FifteenMinutes;
public List<KlineCandleStickResponse> candles=new List<KlineCandleStickResponse>(); public List<KlineCandleStickResponse> candles = new List<KlineCandleStickResponse>();
public List<TAReport> reports = new List<TAReport>(); public List<TAReport> reports = new List<TAReport>();
public List<decimal> resistancePoints = new List<decimal>(); public List<decimal> resistancePoints = new List<decimal>();
public List<decimal> supportPoints = new List<decimal>(); public List<decimal> supportPoints = new List<decimal>();
public event EventHandler<BinanceTradeData> PriceUpdated; public event EventHandler<BinanceTradeData> PriceUpdated;
bool usingCache; 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.pair = pair;
this.index = index; this.index = index;
@ -40,18 +40,23 @@ namespace SignalsTest
void Init() void Init()
{ {
if(usingCache){ if (usingCache)
if(File.Exists(AppDomain.CurrentDomain.BaseDirectory+"/"+pair+".txt")){ {
try{ if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "/" + pair + ".txt"))
{
}catch{ try
{
}
catch
{
} }
} }
} }
// InitLivestream(); // InitLivestream();
KeepUpdatingCandles(); KeepUpdatingCandles();
// TestCallbacks(); // TestCallbacks();
} }
async void TestCallbacks() async void TestCallbacks()
@ -59,25 +64,56 @@ namespace SignalsTest
while (true) while (true)
{ {
await Task.Delay(1000); await Task.Delay(1000);
PriceUpdated?.Invoke(this, new BinanceTradeData() { BestAskPrice=0 }); PriceUpdated?.Invoke(this, new BinanceTradeData() { BestAskPrice = 0 });
} }
} }
async Task UpdateCandles() async Task UpdateCandles()
{ {
GetKlinesCandlesticksRequest req = new GetKlinesCandlesticksRequest(); candles = new List<KlineCandleStickResponse>();
req.Interval = interval;
req.Symbol = pair;
req.EndTime = DateTime.Now;
req.Limit = 150;
candles = await Brian.Client.GetKlinesCandlesticks(req); int rounds = 1;
Console.WriteLine($"Done gettings Kandles for {req.Symbol}, {candles.Count} kandles retreived"); 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; kickstarted = true;
Analyze(req.Symbol); Analyze(pair);
} }
async void Analyze(string symbol){ async void Analyze(string symbol)
{
int[] mas = new int[] { 7, 12, 25 }; int[] mas = new int[] { 7, 12, 25 };
reports = new List<TAReport>(); reports = new List<TAReport>();
decimal max = 0; decimal max = 0;
@ -85,44 +121,54 @@ namespace SignalsTest
decimal maxVol = 0; 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); TAReport report = TAReport.Generate(pair, Utils.GetMinutesForInterval(interval), candles, i, reports);
if(candles[i].Close > max){ if (candles[i].Close > max)
{
max = candles[i].Close; max = candles[i].Close;
} }
if(candles[i].Close < min){ if (candles[i].Close < min)
{
min = candles[i].Close; min = candles[i].Close;
} }
if(candles[i].Volume > maxVol){ if (candles[i].Volume > maxVol)
{
maxVol = candles[i].Volume; maxVol = candles[i].Volume;
} }
reports.Add(report); reports.Add(report);
} }
string lineCalSMA = "SMA20";
resistancePoints =Confirmations.GetResistanceLevels(reports); if(interval!=KlineInterval.FifteenMinutes){
supportPoints = Confirmations.GetSupportiveLevels(reports); 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($"Drawing chart for {reports.Count} candles, Coin: {symbol}, ceil:{max}, floor:{min}");
// Console.WriteLine("Picasso did his job"); // Console.WriteLine("Picasso did his job");
// Console.WriteLine(reports[reports.Count-1].toJson()); // Console.WriteLine(reports[reports.Count-1].toJson());
bool isStSwitch=false; bool isStSwitch = false;
for(int i=0; i< 2; i++){ for (int i = 0; i < 2; i++)
bool _isStSwitch = reports[reports.Count-1-i].STUp != reports[reports.Count-i-2].STUp; {
bool _isStSwitch = reports[reports.Count - 1 - i].STUp != reports[reports.Count - i - 2].STUp;
if(_isStSwitch){ if (_isStSwitch)
isStSwitch=true; {
isStSwitch = true;
break; break;
} }
} }
string triggers = ""; string triggers = "";
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)){ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
triggers+="test"; {
triggers += "test";
} }
// if(isStSwitch){ // if(isStSwitch){
@ -132,20 +178,27 @@ namespace SignalsTest
// triggers += "Price dropped\n"; // triggers += "Price dropped\n";
// } // }
if(reports[reports.Count-2].TWS > 1){ if (reports[reports.Count - 2].TWS > 1)
{
triggers += $"Three White Soldiers appeared"; triggers += $"Three White Soldiers appeared";
} }
if(reports[reports.Count-2].TBC > 1){ if (reports[reports.Count - 2].TBC > 1)
{
triggers += $"Three Black Crows appeared"; triggers += $"Three Black Crows appeared";
} }
if(triggers!= ""){ if (triggers != "")
Picasso.DrawChart(reports, max ,min, maxVol, symbol, interval); {
List<TAReport> limitedReports = new List<TAReport>(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()); Messenger.instance.ScheduleMessage(message, symbol, Utils.GetMinutesForInterval(interval).ToString());
} }
} }
async void KeepUpdatingCandles() async void KeepUpdatingCandles()
@ -154,7 +207,7 @@ namespace SignalsTest
await Task.Delay(delay); await Task.Delay(delay);
UpdateCandles(); UpdateCandles();
while(true) while (true)
{ {
await Task.Delay(60000 + delay); await Task.Delay(60000 + delay);
Console.WriteLine($"Loop call, ({index}) , {DateTime.Now.Minute} = {DateTime.Now.Minute % Utils.GetMinutesForInterval(interval)} "); 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 manualWebsocket = new InstanceBinanceWebSocketClient(Brian.Client);
var socketId = manualWebsocket.ConnectToIndividualSymbolTickerWebSocket(pair, data => var socketId = manualWebsocket.ConnectToIndividualSymbolTickerWebSocket(pair, data =>
{ {
if(candles.Count > 0){ if (candles.Count > 0)
{
candles[candles.Count - 1].Close = data.BestAskPrice; candles[candles.Count - 1].Close = data.BestAskPrice;
} }
}); });

View File

@ -58,7 +58,7 @@ public static class Confirmations
return HeightIncrement; return HeightIncrement;
} }
public static List<decimal> GetSupportiveLevels(List<TAReport> reports, float tolerance = 0.1f, int steps = 5){ public static List<decimal> GetSupportiveLevels(List<TAReport> reports, float tolerance = 0.1f, int steps = 5, string SMA="SMA20"){
List<decimal> allSups = new List<decimal>(); List<decimal> allSups = new List<decimal>();
decimal highest = 0; decimal highest = 0;
@ -76,8 +76,8 @@ public static class Confirmations
if(k <steps * 3){continue;} //not enough history if(k <steps * 3){continue;} //not enough history
bool MATopNow = reports[k].SMA20 > reports[k].candle.High; bool MATopNow = decimal.Parse(Utils.GetPropByName(reports[k], SMA).ToString() ?? "0") > reports[k].candle.High;
bool MATopBefore = reports[k-1].SMA20 > reports[k-1].candle.High; bool MATopBefore = decimal.Parse(Utils.GetPropByName(reports[k-1], SMA).ToString() ?? "0") > reports[k-1].candle.High;
bool MACrossed = MATopBefore!=MATopNow; bool MACrossed = MATopBefore!=MATopNow;
if(!MACrossed){continue;}//No cross if(!MACrossed){continue;}//No cross
@ -108,7 +108,7 @@ public static class Confirmations
return formattedSups; return formattedSups;
} }
public static List<decimal> GetResistanceLevels(List<TAReport> reports, float tolerance = 0.1f, int steps = 5){ public static List<decimal> GetResistanceLevels(List<TAReport> reports, float tolerance = 0.1f, int steps = 5, string SMA="SMA20"){
List<decimal> allResistances = new List<decimal>(); List<decimal> allResistances = new List<decimal>();
decimal highest = 0; decimal highest = 0;
@ -126,8 +126,8 @@ public static class Confirmations
if(k <steps * 3){continue;} //not enough history if(k <steps * 3){continue;} //not enough history
bool MATopNow = reports[k].SMA20 > reports[k].candle.High; bool MATopNow = decimal.Parse(Utils.GetPropByName(reports[k], SMA).ToString() ?? "0") > reports[k].candle.High;
bool MATopBefore = reports[k-1].SMA20 > reports[k-1].candle.High; bool MATopBefore = decimal.Parse(Utils.GetPropByName(reports[k-1], SMA).ToString() ?? "0") > reports[k-1].candle.High;
bool MACrossed = MATopBefore!=MATopNow; bool MACrossed = MATopBefore!=MATopNow;
if(!MACrossed){continue;}//No cross if(!MACrossed){continue;}//No cross

View File

@ -148,4 +148,8 @@ public static class Patterns{
return true; return true;
} }
// public static bool isHammer(KlineCandleStickResponse response, float ratioThreshold = 0.3f){
// }
} }

View File

@ -14,9 +14,27 @@ public class Picasso{
public static void DrawChart(List<TAReport> reports, decimal max, decimal min, decimal volMax, string filename="test", KlineInterval interval = KlineInterval.FifteenMinutes){ public static void DrawChart(List<TAReport> reports, string filename="test", KlineInterval interval = KlineInterval.FifteenMinutes){
// float height = (float)Math.Ceiling(max - min) * 2f; // float height = (float)Math.Ceiling(max - min) * 2f;
// float width = ((float)height / 9f) * 16f; // 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; decimal heightRange = max-min;
float height=1080; float height=1080;
float width = 1920; float width = 1920;
@ -127,15 +145,19 @@ public class Picasso{
#region LINES #region LINES
CoinWatch longestWatch = Brian.GetCoinWatchLongest(filename); List<decimal> allResPoints = Brian.GetCombinedResPoints(filename);
List<decimal> allSupPoints = Brian.GetCombinedSupPoints(filename);
foreach(decimal point in longestWatch.resistancePoints){ List<decimal> processedResPoints = Utils.GetAveragePoints(allResPoints, min,max);
List<decimal> processedSupPoints = Utils.GetAveragePoints(allSupPoints,min,max);
foreach(decimal point in processedResPoints){
float yVal = ((float)(point-min) * heightMultiplier) + candlesOffset; float yVal = ((float)(point-min) * heightMultiplier) + candlesOffset;
// Console.WriteLine($"{filename} res at {yVal/height}"); // Console.WriteLine($"{filename} res at {yVal/height}");
img.Mutate(ctx=> ctx.DrawLine(Color.Red,1f, [new PointF(0, yVal), new PointF(width, yVal)])); 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; float yVal = ((float)(point-min) * heightMultiplier) + candlesOffset;
// Console.WriteLine($"{filename} sup at {yVal/height}"); // Console.WriteLine($"{filename} sup at {yVal/height}");
img.Mutate(ctx=> ctx.DrawLine(Color.Green,1f, [new PointF(0, yVal), new PointF(width, yVal)])); 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(); PathBuilder builder = new PathBuilder();
builder.SetOrigin(new PointF(0,0)); builder.SetOrigin(new PointF(0,0));
for(int i=0; i < reports.Count; i++){ 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); // 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); // Console.WriteLine( prevVal);
float preValY =( prevVal - min) * heightMultiplier ; float preValY =( prevVal - min) * heightMultiplier ;
float newValY=(newVal - min) * heightMultiplier; float newValY=(newVal - min) * heightMultiplier;
@ -198,12 +220,7 @@ public class Picasso{
return builder.Build(); return builder.Build();
} }
static object GetPropByName(TAReport report, string propName){
string json = report.toJson();
Dictionary<string,string> dic = JsonConvert.DeserializeObject<Dictionary<string,string>>(json) ?? new Dictionary<string, string>();
// Console.WriteLine(dic[propName]);
return dic[propName];
}
#endregion #endregion
} }

View File

@ -1,6 +1,7 @@
using BinanceExchange.API.Enums; using BinanceExchange.API.Enums;
using BinanceExchange.API.Models.Response; using BinanceExchange.API.Models.Response;
using BinanceExchange.API.Models.WebSocket; using BinanceExchange.API.Models.WebSocket;
using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -12,7 +13,7 @@ namespace SignalsTest
public class Utils public class Utils
{ {
public static int GetMinutesForInterval(KlineInterval interval) public static int GetMinutesForInterval(KlineInterval interval)
{ {
switch (interval) switch (interval)
{ {
@ -62,6 +63,34 @@ namespace SignalsTest
return response; return response;
} }
public static object GetPropByName(TAReport report, string propName)
{
string json = report.toJson();
Dictionary<string, string> dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(json) ?? new Dictionary<string, string>();
// Console.WriteLine(dic[propName]);
return dic[propName];
}
public static List<decimal> GetAveragePoints(List<decimal> input, decimal min, decimal max){
List<decimal> processed = new List<decimal>();
List<decimal> ignoredPoints = new List<decimal>();
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;
}
} }
} }