Longer time period for logner timeframes, averaged sup and res lines
This commit is contained in:
parent
bf83a4b912
commit
77848e3be4
22
Brian.cs
22
Brian.cs
|
|
@ -56,5 +56,27 @@ namespace SignalsTest
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
112
CoinWatch.cs
112
CoinWatch.cs
|
|
@ -40,11 +40,16 @@ namespace SignalsTest
|
|||
|
||||
void Init()
|
||||
{
|
||||
if(usingCache){
|
||||
if(File.Exists(AppDomain.CurrentDomain.BaseDirectory+"/"+pair+".txt")){
|
||||
try{
|
||||
if (usingCache)
|
||||
{
|
||||
if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "/" + pair + ".txt"))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
}catch{
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -65,19 +70,50 @@ namespace SignalsTest
|
|||
|
||||
async Task UpdateCandles()
|
||||
{
|
||||
GetKlinesCandlesticksRequest req = new GetKlinesCandlesticksRequest();
|
||||
req.Interval = interval;
|
||||
req.Symbol = pair;
|
||||
req.EndTime = DateTime.Now;
|
||||
req.Limit = 150;
|
||||
candles = new List<KlineCandleStickResponse>();
|
||||
|
||||
candles = await Brian.Client.GetKlinesCandlesticks(req);
|
||||
Console.WriteLine($"Done gettings Kandles for {req.Symbol}, {candles.Count} kandles retreived");
|
||||
kickstarted = true;
|
||||
Analyze(req.Symbol);
|
||||
int rounds = 1;
|
||||
int candleLimit = 150;
|
||||
int intervalInMinutes = Utils.GetMinutesForInterval(interval);
|
||||
if (Utils.GetMinutesForInterval(interval) > 50)
|
||||
{
|
||||
rounds = 10;
|
||||
}
|
||||
|
||||
async void Analyze(string symbol){
|
||||
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<TAReport>();
|
||||
decimal max = 0;
|
||||
|
|
@ -85,25 +121,32 @@ 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){
|
||||
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}");
|
||||
|
||||
|
|
@ -111,17 +154,20 @@ namespace SignalsTest
|
|||
// Console.WriteLine(reports[reports.Count-1].toJson());
|
||||
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;
|
||||
|
||||
if(_isStSwitch){
|
||||
if (_isStSwitch)
|
||||
{
|
||||
isStSwitch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
string triggers = "";
|
||||
|
||||
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)){
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
triggers += "test";
|
||||
}
|
||||
|
||||
|
|
@ -132,15 +178,22 @@ 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<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}";
|
||||
Messenger.instance.ScheduleMessage(message, symbol, Utils.GetMinutesForInterval(interval).ToString());
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public static class Confirmations
|
|||
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>();
|
||||
|
||||
decimal highest = 0;
|
||||
|
|
@ -76,8 +76,8 @@ public static class Confirmations
|
|||
|
||||
if(k <steps * 3){continue;} //not enough history
|
||||
|
||||
bool MATopNow = reports[k].SMA20 > 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<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>();
|
||||
|
||||
decimal highest = 0;
|
||||
|
|
@ -126,8 +126,8 @@ public static class Confirmations
|
|||
|
||||
if(k <steps * 3){continue;} //not enough history
|
||||
|
||||
bool MATopNow = reports[k].SMA20 > 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
|
||||
|
|
|
|||
|
|
@ -148,4 +148,8 @@ public static class Patterns{
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
// public static bool isHammer(KlineCandleStickResponse response, float ratioThreshold = 0.3f){
|
||||
|
||||
// }
|
||||
}
|
||||
41
Picasso.cs
41
Picasso.cs
|
|
@ -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 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<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;
|
||||
// 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<string,string> dic = JsonConvert.DeserializeObject<Dictionary<string,string>>(json) ?? new Dictionary<string, string>();
|
||||
// Console.WriteLine(dic[propName]);
|
||||
return dic[propName];
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
29
Utils.cs
29
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;
|
||||
|
|
@ -62,6 +63,34 @@ namespace SignalsTest
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user