183 lines
8.1 KiB
C#
183 lines
8.1 KiB
C#
using SignalsTest;
|
|
using System;
|
|
using SixLabors.Fonts;
|
|
using SixLabors.ImageSharp;
|
|
using SixLabors.ImageSharp.Drawing;
|
|
using SixLabors.ImageSharp.Drawing.Processing;
|
|
using SixLabors.ImageSharp.PixelFormats;
|
|
using SixLabors.ImageSharp.Processing;
|
|
using Newtonsoft.Json;
|
|
|
|
public class Picasso{
|
|
public static void DrawChart(List<TAReport> reports, decimal max, decimal min, decimal volMax, string filename="test"){
|
|
// float height = (float)Math.Ceiling(max - min) * 2f;
|
|
// float width = ((float)height / 9f) * 16f;
|
|
decimal heightRange = max-min;
|
|
float height=1080;
|
|
float width = 1920;
|
|
float widthMultiplier = width / (float)reports.Count;
|
|
float heightMultiplier = (height/ (float)heightRange) * 0.6f;
|
|
|
|
float candlesOffset = 0.3f * height;
|
|
float volumeHeightMultiplier = 0.2f * height;
|
|
using (Image img = new Image<Rgba32>((int)width + 100, (int)height, Color.FromRgb(13,18,25))){
|
|
|
|
#region CANDLES
|
|
for(int i=0; i < reports.Count; i++){
|
|
// img.Mutate(ctx=> ctx.DrawLine()))
|
|
PointF[] points = new PointF[2];
|
|
|
|
float openVal1 = (float)(reports[i].candle.Open - min) * heightMultiplier;
|
|
float closeVal1 = (float)(reports[i].candle.Close - min)* heightMultiplier;
|
|
points[0] =new PointF(i * widthMultiplier, openVal1 + candlesOffset);
|
|
points[1] =new PointF(i * widthMultiplier, closeVal1+ candlesOffset);
|
|
|
|
PointF[] rangePoints = new PointF[2];
|
|
|
|
float highVal = (float)(reports[i].candle.High-min)* heightMultiplier;
|
|
float lowVal = (float)(reports[i].candle.Low-min)* heightMultiplier;
|
|
|
|
rangePoints[0] = new PointF(i * widthMultiplier, highVal+ candlesOffset);
|
|
rangePoints[1] = new PointF(i * widthMultiplier, lowVal+ candlesOffset);
|
|
|
|
PointF[] volumePoints = new PointF[2];
|
|
volumePoints[0] = new PointF(i * widthMultiplier, 0);
|
|
volumePoints[1] = new PointF(i * widthMultiplier, ((float)reports[i].candle.Volume / (float)volMax) * volumeHeightMultiplier);
|
|
|
|
Color candleColor = reports[i].candle.Close > reports[i].candle.Open ? Color.Green : Color.Red;
|
|
|
|
img.Mutate(ctx=> ctx.
|
|
DrawLine(candleColor, 10, points).
|
|
DrawLine(candleColor, 3, rangePoints).
|
|
DrawLine(candleColor, 10, volumePoints)
|
|
);
|
|
|
|
#endregion
|
|
|
|
|
|
float squareOffset = 2;
|
|
|
|
PointF[] bottomPoints = new PointF[2];
|
|
bottomPoints[0] = new PointF(i * widthMultiplier, lowVal-squareOffset+ candlesOffset);
|
|
bottomPoints[1] = new PointF(i * widthMultiplier, lowVal- 15+ candlesOffset);
|
|
|
|
PointF[] topPoints = new PointF[2];
|
|
topPoints[0] = new PointF(i * widthMultiplier, highVal+squareOffset+ candlesOffset);
|
|
topPoints[1] = new PointF(i * widthMultiplier, highVal+15+ candlesOffset);
|
|
|
|
#region TWS
|
|
if(reports[i].TWS > 1){
|
|
Color TWSColor = Color.Blue;
|
|
if(reports[i].TWS == 2){
|
|
TWSColor = Color.Cyan;
|
|
}else if(reports[i].TWS== 3){
|
|
TWSColor = Color.White;
|
|
}
|
|
float TWSHeightIncrement = Confirmations.GetTWSConfirmation(reports,i);
|
|
|
|
PointF[] TWSPoints = bottomPoints;
|
|
TWSPoints[1]-= new PointF(0,TWSHeightIncrement);
|
|
img.Mutate(ctx=>ctx.DrawLine(TWSColor, 10, TWSPoints));
|
|
}
|
|
#endregion
|
|
#region TBC
|
|
if(reports[i].TBC > 1){
|
|
Color TBCColor = Color.Red;
|
|
if(reports[i].TBC == 2){
|
|
TBCColor = Color.Cyan;
|
|
}else if(reports[i].TBC== 3){
|
|
TBCColor = Color.White;
|
|
}
|
|
float TBCHeightIncremenet = Confirmations.GetTBCConfirmation(reports,i);
|
|
|
|
PointF[] TBCPoints = topPoints;
|
|
TBCPoints[1]+= new PointF(0,TBCHeightIncremenet);
|
|
img.Mutate(ctx=>ctx.DrawLine(TBCColor, 10, TBCPoints));
|
|
}
|
|
#endregion
|
|
|
|
}
|
|
// Console.WriteLine("Getting paths");
|
|
// object t = GetPropByName(reports[reports.Count- 1], "SMA7");
|
|
// Console.WriteLine(t);
|
|
// Console.WriteLine(float.Parse(t.ToString()));
|
|
|
|
#region GUIDES
|
|
|
|
PointF[] Vol20 = new PointF[2];
|
|
Vol20[0] = new PointF(0,volumeHeightMultiplier*0.2f);
|
|
Vol20[1] = new PointF(width,volumeHeightMultiplier*0.2f);
|
|
|
|
PointF[] Vol80 = new PointF[2];
|
|
Vol80[0] = new PointF(0, volumeHeightMultiplier*0.8f);
|
|
Vol80[1] = new PointF(width, volumeHeightMultiplier * 0.8f);
|
|
|
|
img.Mutate(ctx=> ctx.DrawLine(Color.Gray, 1f, Vol20).DrawLine(Color.Gray, 0.5f, Vol80));
|
|
|
|
#endregion
|
|
|
|
|
|
#region OVERLAY LINES
|
|
//Overlay - Candles
|
|
IPath sma20Path = GetPath(reports, "SMA20", widthMultiplier,(float)heightMultiplier, (float)min, candlesOffset);
|
|
IPath sma50Path = GetPath(reports, "SMA50", widthMultiplier,(float)heightMultiplier, (float)min, candlesOffset);
|
|
IPath sma200Path = GetPath(reports, "SMA200", widthMultiplier,(float)heightMultiplier, (float)min, candlesOffset);
|
|
|
|
IPath stochFast = GetPath(reports, "Stochastic", widthMultiplier, (float)volumeHeightMultiplier/100f, 0, 0);
|
|
IPath stochK3 = GetPath(reports, "StochasticK3", widthMultiplier, (float)volumeHeightMultiplier/100f, 0, 0);
|
|
|
|
|
|
IPath stPath = GetPath(reports, "ST", widthMultiplier,(float)heightMultiplier, (float)min, candlesOffset);
|
|
#endregion
|
|
//NewChart
|
|
FontFamily fontFamily;
|
|
float TextFontSize = 64f;
|
|
string TextFont = "Noto Sans Mono";
|
|
if (!SystemFonts.TryGet(TextFont, out fontFamily))
|
|
throw new Exception($"Couldn't find font {TextFont}");
|
|
|
|
var font = fontFamily.CreateFont(TextFontSize, FontStyle.Regular);
|
|
|
|
img.Mutate(ctx => ctx.Draw(Color.Yellow, 2, sma20Path).
|
|
Draw(Color.Purple, 2, sma50Path).
|
|
Draw(Color.Cyan, 2, sma200Path).
|
|
Draw(Color.Green, 3, stPath).
|
|
Draw(Color.Cyan, 3,stochFast).
|
|
Draw(Color.Orange, 3, stochK3).
|
|
Flip(FlipMode.Vertical).
|
|
DrawText(filename, font,new Color(Rgba32.ParseHex("#FFFFFF")), new PointF(10,10)));
|
|
|
|
img.Save($"{filename}.png");
|
|
}
|
|
}
|
|
|
|
#region HELPERS
|
|
static IPath GetPath(List<TAReport> reports, string propName, float widthMultiplier,float heightMultiplier, float min, float offset =0){
|
|
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");
|
|
// Console.WriteLine( newVal);
|
|
|
|
float prevVal = i > 0 ? float.Parse(GetPropByName(reports[i-1],propName).ToString() ?? "0") : 0;
|
|
// Console.WriteLine( prevVal);
|
|
float preValY =( prevVal - min) * heightMultiplier ;
|
|
float newValY=(newVal - min) * heightMultiplier;
|
|
PointF prevPoint = new PointF((i-1)* widthMultiplier, (preValY) +offset);
|
|
PointF newPoint = new PointF(i * widthMultiplier, (newValY) + offset);
|
|
// Console.WriteLine(newValY);
|
|
builder.AddLine(prevPoint, newPoint);
|
|
}
|
|
|
|
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
|
|
} |