Charting to build custom chart
Atom
8/8/2017


Hi

I looked at your charting sample and i am interested in building point and figure charts, can you please guide how can i do it , is it possible to override chart.draw to do custom drawing?



Thanks:




4 Answers
Mikhail Sukhov

Avatar
Articles author Programmer Trader
Date: 8/9/2017
Reply


Hello,

Please see our documentation http://doc.stocksharp.co...1d-af29-cf80b633db3c.htm
Thanks:

np74

Avatar
Date: 8/9/2017
Reply


Hi

Thanks for response. I did looked at it but really didnt understood how do i customize it ? The DrawStyle got few possible values but what i am trying is not available as DrawStyle.

It will be very helpful if you could give some pointers - what method or which area i need to look

thanks
Topic starter
Thanks:

Mikhail Sukhov

Avatar
Articles author Programmer Trader
Date: 8/14/2017
Reply


Hello,

Please see the section http://doc.stocksharp.co...1d-af29-cf80b633db3c.htm There is description how to work with Chart component.
Thanks:

np74

Avatar
Date: 8/15/2017
Reply


Hi

I just modified existing sample SampleChartActivOrders as follows to show the pnf chart but i dont see it can you see why? i cant see candle chart though


public partial class MainWindow
{
public ObservableCollection<Order> Orders { get; }

private ChartArea _area;
private ChartCandleElement _candleElement;
private ChartCandleElement _pnfCandleElement;
private ChartActiveOrdersElement _activeOrdersElement;
private TimeFrameCandle _candle;

private readonly DispatcherTimer _chartUpdateTimer = new DispatcherTimer();
private readonly SynchronizedDictionary<DateTimeOffset, TimeFrameCandle> _updatedCandles = new SynchronizedDictionary<DateTimeOffset, TimeFrameCandle>();
private readonly CachedSynchronizedList<TimeFrameCandle> _allCandles = new CachedSynchronizedList<TimeFrameCandle>();
private readonly Dictionary<Order, ChartActiveOrderInfo> _chartOrderInfos = new Dictionary<Order, ChartActiveOrderInfo>();

private const decimal _priceStep = 10m;
private const int _timeframe = 1;

private bool NeedToDelay => _chkDelay.IsChecked == true;
private bool NeedToFail => _chkFail.IsChecked == true;
private bool NeedToConfirm => _chkConfirm.IsChecked == true;

private static readonly TimeSpan _delay = TimeSpan.FromSeconds(2);

private readonly Security _security = new Security
{
Id = "RIZ2@FORTS",
PriceStep = _priceStep,
Board = ExchangeBoard.Forts
};

private readonly ThreadSafeObservableCollection<Portfolio> _portfolios = new ThreadSafeObservableCollection<Portfolio>(new ObservableCollectionEx<Portfolio>
{
new Portfolio
{
Name = "Test portfolio"
}
});

private PnFArg _pngArg = new PnFArg()
{
BoxSize = 20,
ReversalAmount = 3
};
public MainWindow()
{
ConfigManager.RegisterService(_portfolios);

Orders = new ObservableCollection<Order>();
InitializeComponent();
Loaded += OnLoaded;

Chart.OrderSettings.Security = _security;
Chart.OrderSettings.Portfolio = _portfolios.First();
Chart.OrderSettings.Volume = 5;

_chartUpdateTimer.Interval = TimeSpan.FromMilliseconds(10000);
_chartUpdateTimer.Tick += ChartUpdateTimerOnTick;
_chartUpdateTimer.Start();
}

private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
InitCharts();
LoadData(@"..\..\..\..\Testing\HistoryData\".ToFullPath());
}

private void InitCharts()
{
Chart.ClearAreas();
Chart.OrderCreationMode = true;

_area = new ChartArea();

var yAxis = _area.YAxises.First();

yAxis.AutoRange = true;
Chart.IsAutoRange = true;
Chart.IsAutoScroll = true;

Chart.AddArea(_area);

var series = new CandleSeries(
typeof(TimeFrameCandle),
_security,
TimeSpan.FromMinutes(_timeframe));




var pnfSeries = new CandleSeries(
typeof(PnFCandle),
_security,
_pngArg);

_candleElement = new ChartCandleElement
{
FullTitle = "Candles"
};
Chart.AddElement(_area, _candleElement, series);

_pnfCandleElement = new ChartCandleElement
{
FullTitle = "PNF"
};
Chart.AddElement(_area, _pnfCandleElement, pnfSeries);

_activeOrdersElement = new ChartActiveOrdersElement
{
FullTitle = "Active orders"
};
Chart.AddElement(_area, _activeOrdersElement);
}

private void LoadData(string path)
{
_candle = null;
_allCandles.Clear();

Chart.Reset(new IChartElement[] { _candleElement, _activeOrdersElement });
//Chart.Reset(new IChartElement[] { _pnfCandleElement, _activeOrdersElement });

var storage = new StorageRegistry();

var maxDays = 2;

BusyIndicator.IsBusy = true;

Task.Factory.StartNew(() =>
{
var date = DateTime.MinValue;

foreach (var tick in storage.GetTickMessageStorage(_security, new LocalMarketDataDrive(path)).Load())
{
AppendTick(_security, tick);

if (date != tick.ServerTime.Date)
{
date = tick.ServerTime.Date;

this.GuiAsync(() =>
{
BusyIndicator.BusyContent = date.ToString();
});

maxDays--;

if (maxDays == 0)
break;
}
}
})
.ContinueWith(t =>
{
if (t.Exception != null)
Error(t.Exception.Message);

this.GuiAsync(() =>
{
BusyIndicator.IsBusy = false;
Chart.IsAutoRange = false;
_area.YAxises.First().AutoRange = false;

Log($"Loaded {_allCandles.Count} candles");
});

}, TaskScheduler.FromCurrentSynchronizationContext());
}

private void ChartUpdateTimerOnTick(object sender, EventArgs eventArgs)
{
TimeFrameCandle[] candlesToUpdate;

lock (_updatedCandles.SyncRoot)
{
candlesToUpdate = _updatedCandles.OrderBy(p => p.Key).Select(p => p.Value).ToArray();
_updatedCandles.Clear();
}

var lastCandle = _allCandles.LastOrDefault();
_allCandles.AddRange(candlesToUpdate.Where(c => lastCandle == null || c.OpenTime != lastCandle.OpenTime));

var data = new ChartDrawData();
PnFCandle prevCandle = null;
foreach (var candle in candlesToUpdate)
{
if(prevCandle ==null)
{
PnFCandle newCandle = new PnFCandle()
{
Security = candle.Security,
CloseTime = candle.CloseTime,
HighTime = candle.HighTime,
OpenTime = candle.OpenTime,
ClosePrice = candle.ClosePrice,
OpenPrice = candle.OpenPrice,
HighPrice = candle.HighPrice,
LowPrice = candle.LowPrice,
TotalVolume = candle.TotalVolume,


};
newCandle.PnFArg = _pngArg;
newCandle.Type = PnFTypes.X;
prevCandle = newCandle;
data.Group(candle.OpenTime).Add(_pnfCandleElement, newCandle);
}
else
{
if( prevCandle.Type == PnFTypes.X)
{
if( candle.ClosePrice - prevCandle.ClosePrice >= _pngArg.BoxSize)
{
PnFCandle newCandle = new PnFCandle()
{
Security = candle.Security,
CloseTime = candle.CloseTime,
HighTime = candle.HighTime,
OpenTime = candle.OpenTime,
ClosePrice = candle.ClosePrice,
OpenPrice = candle.OpenPrice,
HighPrice = candle.HighPrice,
LowPrice = candle.LowPrice,
TotalVolume = candle.TotalVolume,
PnFArg = _pngArg,
Type = PnFTypes.X,
};
prevCandle = newCandle;
data.Group(candle.OpenTime).Add(_pnfCandleElement, newCandle);
}
else if(candle.ClosePrice - prevCandle.ClosePrice <= _pngArg.BoxSize * _pngArg.ReversalAmount)
{
PnFCandle newCandle = new PnFCandle()
{
Security = candle.Security,
CloseTime = candle.CloseTime,
HighTime = candle.HighTime,
OpenTime = candle.OpenTime,
ClosePrice = candle.ClosePrice,
OpenPrice = candle.OpenPrice,
HighPrice = candle.HighPrice,
LowPrice = candle.LowPrice,
TotalVolume = candle.TotalVolume,
PnFArg = _pngArg,
Type = PnFTypes.O,
};
prevCandle = newCandle;
data.Group(candle.OpenTime).Add(_pnfCandleElement, newCandle);
}

}
else if (prevCandle.Type == PnFTypes.O)
{
if (candle.ClosePrice - prevCandle.ClosePrice <= _pngArg.BoxSize)
{
PnFCandle newCandle = new PnFCandle()
{
Security = candle.Security,
CloseTime = candle.CloseTime,
HighTime = candle.HighTime,
OpenTime = candle.OpenTime,
ClosePrice = candle.ClosePrice,
OpenPrice = candle.OpenPrice,
HighPrice = candle.HighPrice,
LowPrice = candle.LowPrice,
TotalVolume = candle.TotalVolume,
PnFArg = _pngArg,
Type = PnFTypes.O,
};
prevCandle = newCandle;
data.Group(candle.OpenTime).Add(_pnfCandleElement, newCandle);
}
else if (candle.ClosePrice - prevCandle.ClosePrice >= _pngArg.BoxSize * _pngArg.ReversalAmount)
{
PnFCandle newCandle = new PnFCandle()
{
Security = candle.Security,
CloseTime = candle.CloseTime,
HighTime = candle.HighTime,
OpenTime = candle.OpenTime,
ClosePrice = candle.ClosePrice,
OpenPrice = candle.OpenPrice,
HighPrice = candle.HighPrice,
LowPrice = candle.LowPrice,
TotalVolume = candle.TotalVolume,
PnFArg = _pngArg,
Type = PnFTypes.X,
};
prevCandle = newCandle;
data.Group(candle.OpenTime).Add(_pnfCandleElement, newCandle);
}

}
}
}

Chart.Draw(data);
}

private void AppendTick(Security security, ExecutionMessage tick)
{
var time = tick.ServerTime;
var price = tick.TradePrice.Value;

if (_candle == null || time >= _candle.CloseTime)
{
if (_candle != null)
{
_candle.State = CandleStates.Finished;
lock (_updatedCandles.SyncRoot)
_updatedCandles[_candle.OpenTime] = _candle;
}

var tf = TimeSpan.FromMinutes(_timeframe);
var bounds = tf.GetCandleBounds(time, _security.Board);
_candle = new TimeFrameCandle
{
TimeFrame = tf,
OpenTime = bounds.Min,
CloseTime = bounds.Max,
Security = security,
};

_candle.OpenPrice = _candle.HighPrice = _candle.LowPrice = _candle.ClosePrice = price;
}

if (time < _candle.OpenTime)
throw new InvalidOperationException("invalid time");

if (price > _candle.HighPrice)
_candle.HighPrice = price;

if (price < _candle.LowPrice)
_candle.LowPrice = price;

_candle.ClosePrice = price;

_candle.TotalVolume += tick.TradeVolume.Value;

lock (_updatedCandles.SyncRoot)
_updatedCandles[_candle.OpenTime] = _candle;
}
Topic starter
Thanks:


Attach files by dragging & dropping, , or pasting from the clipboard.

loading
clippy