345 lines
18 KiB
C#
345 lines
18 KiB
C#
using DataDisplay.Common;
|
|
using DataDisplay.DataSource;
|
|
using DataDisplay.Graph;
|
|
using DataDisplay.Renderers;
|
|
using SkiaSharp;
|
|
using System;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
using MarketData.Utils;
|
|
using MarketData.MarketDataModel;
|
|
|
|
namespace Navigator.Renderers
|
|
{
|
|
public class BollingerBandRenderer : IRenderer
|
|
{
|
|
private SKPaint paintK=new SKPaint{Style=SKPaintStyle.StrokeAndFill,Color=new SKColor((uint)SKColors.Green),StrokeWidth=5f};
|
|
private SKPaint paintL=new SKPaint{Style=SKPaintStyle.StrokeAndFill,Color=new SKColor((uint)SKColors.Green),StrokeWidth=5f};
|
|
private SKPaint paintKL1=new SKPaint{Style=SKPaintStyle.StrokeAndFill,Color=new SKColor((uint)SKColors.Green),StrokeWidth=3f};
|
|
private SKPaint paintLP1=new SKPaint{Style=SKPaintStyle.StrokeAndFill,Color=new SKColor((uint)SKColors.Green),StrokeWidth=3f};
|
|
private SKPaint paintHigh=new SKPaint{Style=SKPaintStyle.StrokeAndFill,Color=new SKColor((uint)SKColors.Blue),StrokeWidth=4f};
|
|
private SKPaint paintLow=new SKPaint{Style=SKPaintStyle.StrokeAndFill,Color=new SKColor((uint)SKColors.Red),StrokeWidth=4f};
|
|
private SKPaint paintClose=new SKPaint{Style=SKPaintStyle.StrokeAndFill,Color=new SKColor((uint)SKColors.Black),StrokeWidth=5f};
|
|
private SKPaint paintSMAN=new SKPaint{Style=SKPaintStyle.StrokeAndFill,Color=new SKColor((uint)SKColors.Purple),StrokeWidth=3f};
|
|
private SKPaint paintPointMarkerStroke=new SKPaint{Style=SKPaintStyle.Stroke,Color=new SKColor((uint)SKColors.Black),StrokeWidth=3f};
|
|
private SKPaint paintPointMarkerFill=new SKPaint{Style=SKPaintStyle.Fill,Color=new SKColor((uint)SKColors.Yellow),StrokeWidth=3f};
|
|
private SKPaint paintParityPricePointMarkerStroke=new SKPaint{Style=SKPaintStyle.Stroke,Color=new SKColor((uint)SKColors.Black),StrokeWidth=3f};
|
|
private SKPaint paintParityPricePointMarkerFill=new SKPaint{Style=SKPaintStyle.Fill,Color=new SKColor((uint)SKColors.DarkBlue),StrokeWidth=3f};
|
|
private SKPaint paintStopLimitMarkerStroke=new SKPaint{Style=SKPaintStyle.Stroke,Color=new SKColor((uint)SKColors.Black),StrokeWidth=3f};
|
|
private SKPaint paintStopLimitMarkerFill=new SKPaint{Style=SKPaintStyle.Fill,Color=new SKColor((uint)SKColors.Red),StrokeWidth=3f};
|
|
|
|
public enum Band{K=0,KL1=1,L=2,LP1=3,High=4,Low=5,Close=6,SMAN=7};
|
|
private Dictionary<int,LineGraph> bollingerBandGraphs=new Dictionary<int,LineGraph>();
|
|
private PortfolioTradesWithParityPrice portfolioTradesWithParityPrice;
|
|
private StopLimit stopLimit;
|
|
private DateGenerator dateGenerator=new DateGenerator();
|
|
private bool deviceIsTablet=false;
|
|
|
|
public BollingerBandRenderer()
|
|
{
|
|
}
|
|
|
|
public void SetPaint(SKPaint paint,Band band)
|
|
{
|
|
if(!bollingerBandGraphs.ContainsKey((int)band))return;
|
|
bollingerBandGraphs[(int)band].SetPaint(paint);
|
|
}
|
|
|
|
public bool DeviceIsTablet
|
|
{
|
|
get{return deviceIsTablet;}
|
|
set{deviceIsTablet=value;}
|
|
}
|
|
|
|
public StopLimit StopLimit
|
|
{
|
|
get{return stopLimit;}
|
|
set{stopLimit=value;}
|
|
}
|
|
|
|
public PortfolioTradesWithParityPrice PortfolioTradesWithParityPrice
|
|
{
|
|
get{return portfolioTradesWithParityPrice;}
|
|
set
|
|
{
|
|
portfolioTradesWithParityPrice=value;
|
|
if(null!=portfolioTradesWithParityPrice)PortfolioTrades=portfolioTradesWithParityPrice.Trades;
|
|
}
|
|
}
|
|
private PortfolioTrades PortfolioTrades{get;set;}
|
|
|
|
public CompositeDataSource K
|
|
{
|
|
set
|
|
{
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.K))bollingerBandGraphs[(int)Band.K].SetDataSource(value);
|
|
else bollingerBandGraphs.Add((int)Band.K,new LineGraph(paintK,value));
|
|
}
|
|
}
|
|
|
|
public CompositeDataSource KL1
|
|
{
|
|
set
|
|
{
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.KL1))bollingerBandGraphs[(int)Band.KL1].SetDataSource(value);
|
|
else bollingerBandGraphs.Add((int)Band.KL1,new LineGraph(paintKL1,value));
|
|
}
|
|
}
|
|
|
|
public CompositeDataSource L
|
|
{
|
|
set
|
|
{
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.L))bollingerBandGraphs[(int)Band.L].SetDataSource(value);
|
|
else bollingerBandGraphs.Add((int)Band.L,new LineGraph(paintL,value));
|
|
}
|
|
}
|
|
|
|
public CompositeDataSource LP1
|
|
{
|
|
set
|
|
{
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))bollingerBandGraphs[(int)Band.LP1].SetDataSource(value);
|
|
else bollingerBandGraphs.Add((int)Band.LP1,new LineGraph(paintLP1,value));
|
|
}
|
|
}
|
|
|
|
public CompositeDataSource High
|
|
{
|
|
set
|
|
{
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.High))bollingerBandGraphs[(int)Band.High].SetDataSource(value);
|
|
else bollingerBandGraphs.Add((int)Band.High,new LineGraph(paintHigh,value));
|
|
}
|
|
}
|
|
|
|
public CompositeDataSource Low
|
|
{
|
|
set
|
|
{
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Low))bollingerBandGraphs[(int)Band.Low].SetDataSource(value);
|
|
else bollingerBandGraphs.Add((int)Band.Low,new LineGraph(paintLow,value));
|
|
}
|
|
}
|
|
|
|
public CompositeDataSource Close
|
|
{
|
|
set
|
|
{
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Close))bollingerBandGraphs[(int)Band.Close].SetDataSource(value);
|
|
else bollingerBandGraphs.Add((int)Band.Close,new LineGraph(paintClose,value));
|
|
}
|
|
}
|
|
|
|
private Type GetXDataType()
|
|
{
|
|
return typeof(DateTime);
|
|
}
|
|
|
|
private Type GetYDataType()
|
|
{
|
|
return typeof(double);
|
|
}
|
|
|
|
//*********************************************************************************************************************************************************************
|
|
public CompositeDataSource SMAN
|
|
{
|
|
set
|
|
{
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.SMAN))bollingerBandGraphs[(int)Band.SMAN].SetDataSource(value);
|
|
else bollingerBandGraphs.Add((int)Band.SMAN,new LineGraph(paintSMAN,value));
|
|
}
|
|
}
|
|
|
|
public void Refresh()
|
|
{
|
|
RefreshRequested?.Invoke(this, EventArgs.Empty);
|
|
}
|
|
// ************************************************************************************************************************************
|
|
// ********************************************************* R E N D E R E R *********************************************************
|
|
// ************************************************************************************************************************************
|
|
public void PaintSurface(SKSurface surface,SKImageInfo imageInfo)
|
|
{
|
|
SKCanvas canvas = surface.Canvas;
|
|
canvas.Clear();
|
|
if(!AnyData())return;
|
|
|
|
int width=imageInfo.Width;
|
|
int height=imageInfo.Height;
|
|
|
|
XDataExtent=GetXDataExtent();
|
|
YDataExtent=GetYDataExtent();
|
|
XDataExtentMin=GetXDataExtentMin();
|
|
YDataExtentMin=GetYDataExtentMin();
|
|
|
|
PointMapping pointMapping=new PointMapping(width,height,XDataExtent,XDataExtentMin,YDataExtent,YDataExtentMin,80,50);
|
|
|
|
GridLines gridLines=new GridLines(10,10);
|
|
gridLines.AssignXDataType=GetXDataType;
|
|
gridLines.AssignGetYDataType=GetYDataType;
|
|
gridLines.Render(canvas,pointMapping);
|
|
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.K))bollingerBandGraphs[(int)Band.K].Render(canvas,pointMapping);
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.KL1))bollingerBandGraphs[(int)Band.KL1].Render(canvas,pointMapping);
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.L))bollingerBandGraphs[(int)Band.L].Render(canvas,pointMapping);
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))bollingerBandGraphs[(int)Band.LP1].Render(canvas,pointMapping);
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))bollingerBandGraphs[(int)Band.LP1].Render(canvas,pointMapping);
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.High))bollingerBandGraphs[(int)Band.High].Render(canvas,pointMapping);
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Low))bollingerBandGraphs[(int)Band.Low].Render(canvas,pointMapping);
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Close))bollingerBandGraphs[(int)Band.Close].Render(canvas,pointMapping);
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.SMAN))bollingerBandGraphs[(int)Band.SMAN].Render(canvas,pointMapping);
|
|
|
|
RenderPositionPointMarkers(canvas,pointMapping,paintPointMarkerStroke,paintPointMarkerFill);
|
|
RenderParityPricePointMarker(canvas,pointMapping,paintParityPricePointMarkerStroke,paintParityPricePointMarkerFill);
|
|
RenderStopLimitPointMarker(canvas,pointMapping,paintStopLimitMarkerStroke,paintStopLimitMarkerFill);
|
|
}
|
|
|
|
public void RenderPositionPointMarkers(SKCanvas canvas,PointMapping pointMapping,SKPaint paintPointMarkerStroke,SKPaint paintPointMarkerFill)
|
|
{
|
|
if(null==PortfolioTrades||0==PortfolioTrades.Count)return;
|
|
DateTime minVisibleDate=new DateTime((long)(pointMapping.XDataExtentMin*10000000000.0));
|
|
DateTime maxVisibleDate=new DateTime((long)(pointMapping.XDataExtent*10000000000.0));
|
|
|
|
minVisibleDate=dateGenerator.FindPrevBusinessDay(minVisibleDate); // subtract an extra business day to the extent to handle edge cases
|
|
maxVisibleDate=dateGenerator.FindNextBusinessDay(maxVisibleDate); // add an extra business day to the extent to handle edge cases.
|
|
List<PortfolioTrade> portfolioTrades=PortfolioTrades.Where(x=>x.TradeDate>=minVisibleDate && x.TradeDate<=maxVisibleDate).ToList();
|
|
foreach(PortfolioTrade portfolioTrade in portfolioTrades)
|
|
{
|
|
SKPoint tradePoint=new SKPoint((float)(portfolioTrade.TradeDate.Ticks/10000000000.0),(float)portfolioTrade.Price);
|
|
tradePoint=pointMapping.MapPoint(tradePoint);
|
|
DrawTriangle(canvas,tradePoint,paintPointMarkerStroke,paintPointMarkerFill);
|
|
}
|
|
}
|
|
|
|
public void RenderParityPricePointMarker(SKCanvas canvas,PointMapping pointMapping,SKPaint parityPricePointMarkerStroke,SKPaint parityPricePointMarkerFill)
|
|
{
|
|
if(null==PortfolioTradesWithParityPrice||null==PortfolioTradesWithParityPrice.ParityPrice)return;
|
|
SKPoint parityPoint=new SKPoint((float)(portfolioTradesWithParityPrice.ParityPrice.Date.Ticks/10000000000.0),(float)portfolioTradesWithParityPrice.ParityPrice.Close);
|
|
parityPoint=pointMapping.MapPoint(parityPoint);
|
|
DrawTriangle(canvas,parityPoint,parityPricePointMarkerStroke,parityPricePointMarkerFill);
|
|
}
|
|
|
|
public void RenderStopLimitPointMarker(SKCanvas canvas,PointMapping pointMapping,SKPaint stopLimitPointMarkerStroke,SKPaint stopLimitPointMarkerFill)
|
|
{
|
|
if(null==stopLimit)return;
|
|
SKPoint stopLimitPoint=new SKPoint((float)(pointMapping.XDataExtent),(float)stopLimit.StopPrice);
|
|
stopLimitPoint=pointMapping.MapPoint(stopLimitPoint);
|
|
DrawTriangle(canvas,stopLimitPoint,stopLimitPointMarkerStroke,stopLimitPointMarkerFill);
|
|
}
|
|
|
|
public void DrawTriangle(SKCanvas canvas,SKPoint point,SKPaint paintStrokeMarker,SKPaint paintFillMarker)
|
|
{
|
|
double baseLength = 50;
|
|
if(DeviceIsTablet)baseLength*=.45;
|
|
DrawingHelper.DrawIsoTriangle(canvas, point, (int)baseLength, paintStrokeMarker, paintFillMarker);
|
|
}
|
|
|
|
public double XDataExtent{get;set;}
|
|
|
|
public double XDataExtentMin{get;set;}
|
|
|
|
public double XRange{get{return XDataExtent-XDataExtentMin;}}
|
|
|
|
public double YDataExtent{get;set;}
|
|
|
|
public double YDataExtentMin{get;set;}
|
|
|
|
public double YRange{get{return YDataExtent-YDataExtentMin;}}
|
|
|
|
private bool AnyData()
|
|
{
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.K))return true;
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.KL1))return true;
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.L))return true;
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))return true;
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))return true;
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.High))return true;
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Low))return true;
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Close))return true;
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.SMAN))return true;
|
|
return false;
|
|
}
|
|
|
|
private double GetXDataExtent()
|
|
{
|
|
List<double> xExtents=new List<double>();
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.K))xExtents.Add(bollingerBandGraphs[(int)Band.K].GetXExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.KL1))xExtents.Add(bollingerBandGraphs[(int)Band.KL1].GetXExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.L))xExtents.Add(bollingerBandGraphs[(int)Band.L].GetXExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))xExtents.Add(bollingerBandGraphs[(int)Band.LP1].GetXExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))xExtents.Add(bollingerBandGraphs[(int)Band.LP1].GetXExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.High))xExtents.Add(bollingerBandGraphs[(int)Band.High].GetXExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Low))xExtents.Add(bollingerBandGraphs[(int)Band.Low].GetXExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Close))xExtents.Add(bollingerBandGraphs[(int)Band.Close].GetXExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.SMAN))xExtents.Add(bollingerBandGraphs[(int)Band.SMAN].GetXExtent());
|
|
return xExtents.Count>0?xExtents.Max(x=>x):0;
|
|
}
|
|
|
|
private double GetXDataExtentMin()
|
|
{
|
|
List<double> xExtents=new List<double>();
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.K))xExtents.Add(bollingerBandGraphs[(int)Band.K].GetXExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.KL1))xExtents.Add(bollingerBandGraphs[(int)Band.KL1].GetXExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.L))xExtents.Add(bollingerBandGraphs[(int)Band.L].GetXExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))xExtents.Add(bollingerBandGraphs[(int)Band.LP1].GetXExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))xExtents.Add(bollingerBandGraphs[(int)Band.LP1].GetXExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.High))xExtents.Add(bollingerBandGraphs[(int)Band.High].GetXExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Low))xExtents.Add(bollingerBandGraphs[(int)Band.Low].GetXExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Close))xExtents.Add(bollingerBandGraphs[(int)Band.Close].GetXExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.SMAN))xExtents.Add(bollingerBandGraphs[(int)Band.SMAN].GetXExtentMin());
|
|
return xExtents.Count>0?xExtents.Min(x=>x):0;
|
|
}
|
|
|
|
private double GetYDataExtent()
|
|
{
|
|
List<double> yExtents=new List<double>();
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.K))yExtents.Add(bollingerBandGraphs[(int)Band.K].GetYExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.KL1))yExtents.Add(bollingerBandGraphs[(int)Band.KL1].GetYExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.L))yExtents.Add(bollingerBandGraphs[(int)Band.L].GetYExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))yExtents.Add(bollingerBandGraphs[(int)Band.LP1].GetYExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))yExtents.Add(bollingerBandGraphs[(int)Band.LP1].GetYExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.High))yExtents.Add(bollingerBandGraphs[(int)Band.High].GetYExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Low))yExtents.Add(bollingerBandGraphs[(int)Band.Low].GetYExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Close))yExtents.Add(bollingerBandGraphs[(int)Band.Close].GetYExtent());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.SMAN))yExtents.Add(bollingerBandGraphs[(int)Band.SMAN].GetYExtent());
|
|
if(null!=portfolioTradesWithParityPrice&&null!=portfolioTradesWithParityPrice.ParityPrice)
|
|
{
|
|
yExtents.Add(portfolioTradesWithParityPrice.ParityPrice.Close);
|
|
}
|
|
if(null!=stopLimit)
|
|
{
|
|
yExtents.Add(stopLimit.StopPrice);
|
|
}
|
|
double maxDataExtent=yExtents.Count>0?yExtents.Max(x=>x):0;
|
|
return maxDataExtent;
|
|
}
|
|
|
|
private double GetYDataExtentMin()
|
|
{
|
|
List<double> yExtents=new List<double>();
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.K))yExtents.Add(bollingerBandGraphs[(int)Band.K].GetYExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.KL1))yExtents.Add(bollingerBandGraphs[(int)Band.KL1].GetYExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.L))yExtents.Add(bollingerBandGraphs[(int)Band.L].GetYExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))yExtents.Add(bollingerBandGraphs[(int)Band.LP1].GetYExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.LP1))yExtents.Add(bollingerBandGraphs[(int)Band.LP1].GetYExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.High))yExtents.Add(bollingerBandGraphs[(int)Band.High].GetYExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Low))yExtents.Add(bollingerBandGraphs[(int)Band.Low].GetYExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.Close))yExtents.Add(bollingerBandGraphs[(int)Band.Close].GetYExtentMin());
|
|
if(bollingerBandGraphs.ContainsKey((int)Band.SMAN))yExtents.Add(bollingerBandGraphs[(int)Band.SMAN].GetYExtentMin());
|
|
|
|
if(null!=portfolioTradesWithParityPrice&&null!=portfolioTradesWithParityPrice.ParityPrice)
|
|
{
|
|
yExtents.Add(portfolioTradesWithParityPrice.ParityPrice.Close);
|
|
}
|
|
if(null!=stopLimit)
|
|
{
|
|
yExtents.Add(stopLimit.StopPrice);
|
|
}
|
|
double minDataExtent=yExtents.Count>0?yExtents.Min(x=>x):0;
|
|
return minDataExtent;
|
|
}
|
|
|
|
public event EventHandler RefreshRequested;
|
|
}
|
|
}
|