mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-02 11:37:42 +00:00
Update JMA_chart indicator to use Indicator base class and add painting logic
This commit is contained in:
@@ -13,46 +13,75 @@ EQUITY - Generates P&L portfolio based on trades signals and equity prices
|
||||
//optional: warmup period: warmup
|
||||
|
||||
public class EQUITY_Series : Single_TSeries_Indicator {
|
||||
int trade_state = 0;
|
||||
readonly int _warmup = 0;
|
||||
double eq_value = 0;
|
||||
readonly TSeries _prices;
|
||||
readonly bool _long, _short;
|
||||
public EQUITY_Series(TSeries trades, TSeries prices, bool Long = true, bool Short = false, int Warmup = 0) : base(trades, period: 0, useNaN: false) {
|
||||
_prices = prices;
|
||||
_long = Long;
|
||||
_short = Short;
|
||||
_warmup = Warmup;
|
||||
readonly TSeries inmarket; //for every bar
|
||||
private readonly TSeries _price;
|
||||
private double _equity;
|
||||
private readonly double _capital;
|
||||
|
||||
readonly int _warmup;
|
||||
double _cash;
|
||||
int _units;
|
||||
private bool _longbuy, _longsell;
|
||||
double _long_order, _open_order;
|
||||
double _investment_value;
|
||||
short _inmarket;
|
||||
|
||||
public EQUITY_Series(TSeries signal, TSeries price, int warmup = 0, double capital = 1000) : base(signal, period: 0, useNaN: false) {
|
||||
_capital = capital;
|
||||
_cash = _capital;
|
||||
_investment_value = 0;
|
||||
_warmup = (warmup > 0) ? warmup : 1;
|
||||
|
||||
inmarket = new();
|
||||
_longbuy = _longsell = false;
|
||||
_open_order = 0;
|
||||
_inmarket = 0;
|
||||
_units = 0;
|
||||
_long_order = 0;
|
||||
|
||||
_price = price; //we buy on the Open price of the NEXT bar
|
||||
_long_order = 0;
|
||||
|
||||
if (base._data.Count > 0) { base.Add(base._data); }
|
||||
}
|
||||
|
||||
public override void Add((System.DateTime t, double v) TValue, bool update) {
|
||||
if (this.Count != 0)
|
||||
eq_value = this[this.Count - 1].v;
|
||||
|
||||
//buy signal
|
||||
if (TValue.v == 1 && this.Count > _warmup) {
|
||||
//we are not in-market and we can do long trades
|
||||
if (_short) { trade_state = 0; }
|
||||
if (_long) { trade_state = 1; }
|
||||
if (this.Count > _warmup) {
|
||||
|
||||
// harvest the gain-loss from previous day
|
||||
_investment_value = _units * _price[this.Count - 1].v;
|
||||
_equity = _cash + _investment_value;
|
||||
|
||||
|
||||
//execute orders from previous bar
|
||||
if (_longbuy && _inmarket == 0) { //time to execute the long buy
|
||||
_units = (int)(_cash / _price[this.Count - 1].v);
|
||||
_long_order = _units * _price[this.Count - 1].v;
|
||||
_cash -= _long_order;
|
||||
_open_order = _long_order;
|
||||
_equity = _cash + _open_order;
|
||||
_inmarket = 1;
|
||||
_longbuy = false;
|
||||
}
|
||||
|
||||
if (_longsell && _inmarket == 1) { //time to execute the long sell
|
||||
_long_order = (_units * _price[this.Count - 1].v);
|
||||
_cash += _long_order;
|
||||
_units = 0;
|
||||
|
||||
_open_order = 0;
|
||||
_equity = _cash + _open_order;
|
||||
_inmarket = 0;
|
||||
_longsell = false;
|
||||
}
|
||||
|
||||
if (_inmarket == 0 && TValue.v == 1) { _longbuy = true; } //out of market, enter long
|
||||
if (_inmarket == 1 && TValue.v == -1) { _longsell = true; } //long market, exit long
|
||||
|
||||
//Console.WriteLine($"{TValue.v,3}\t {(_inmarket)} : {_cash,10:f2} + {_units*_price[this.Count-1].v,7:f2} = {_equity-_capital:f2}");
|
||||
}
|
||||
|
||||
//sell signal
|
||||
if (TValue.v == -1 && this.Count > _warmup) {
|
||||
//we are in-market and we can do long trades
|
||||
if (_long) { trade_state = 0; }
|
||||
if (_short) { trade_state = -1; }
|
||||
}
|
||||
|
||||
if (trade_state == 1) {
|
||||
eq_value = this[this.Count - 1].v + (_prices[this.Count].v - _prices[this.Count - 1].v);
|
||||
|
||||
}
|
||||
|
||||
if (trade_state == -1) {
|
||||
eq_value = this[this.Count - 1].v + (_prices[this.Count - 1].v - _prices[this.Count].v);
|
||||
|
||||
}
|
||||
base.Add((TValue.t, eq_value), update, _NaN);
|
||||
inmarket.Add(TValue.t, (double)_inmarket);
|
||||
base.Add((TValue.t, _equity), update, _NaN);
|
||||
}
|
||||
}
|
||||
@@ -55,9 +55,6 @@ public class DEMA_Series : Single_TSeries_Indicator
|
||||
}
|
||||
else if (_len <= _period && _useSMA && _period != 0) {
|
||||
_sum += TValue.v;
|
||||
if (_period != 0 && _len > _period) {
|
||||
_sum -= (_data[base.Count - _period - (update ? 1 : 0)].v);
|
||||
}
|
||||
_ema1 = _sum / Math.Min(_len, _period);
|
||||
_ema2 = _ema1;
|
||||
}
|
||||
|
||||
@@ -97,8 +97,8 @@ public class JMA_Series : Single_TSeries_Indicator {
|
||||
/// from avolty to rolty
|
||||
double rvolty = (avolty != 0) ? volty / avolty : 0;
|
||||
double len1 = (Math.Log(Math.Sqrt(_p)) / Math.Log(2.0)) + 2;
|
||||
if (len1 < 0)
|
||||
len1 = 0;
|
||||
if (len1 < 0) { len1 = 0; }
|
||||
|
||||
double pow1 = Math.Max(len1 - 2.0, 0.5);
|
||||
if (rvolty > Math.Pow(len1, 1.0 / pow1)) { rvolty = Math.Pow(len1, 1.0 / pow1); }
|
||||
if (rvolty < 1) { rvolty = 1; }
|
||||
|
||||
@@ -26,7 +26,7 @@ public class CMO_Series : Single_TSeries_Indicator {
|
||||
|
||||
public override void Add((DateTime t, double v) TValue, bool update) {
|
||||
if (this.Count == 0) { _plast_value = _last_value = TValue.v; }
|
||||
if (update) _last_value = _plast_value; else _plast_value = _last_value;
|
||||
if (update) {_last_value = _plast_value;} else {_plast_value = _last_value;}
|
||||
|
||||
Add_Replace_Trim(_buff_up, (TValue.v > _last_value) ? TValue.v-_last_value : 0, _p, update);
|
||||
Add_Replace_Trim(_buff_dn, (TValue.v < _last_value) ? _last_value-TValue.v : 0, _p, update);
|
||||
@@ -40,8 +40,7 @@ public class CMO_Series : Single_TSeries_Indicator {
|
||||
}
|
||||
|
||||
double _cmo = 100 * (_cmo_up - _cmo_dn) / (_cmo_up + _cmo_dn);
|
||||
if (_cmo_up + _cmo_dn == 0)
|
||||
_cmo = 0;
|
||||
if (_cmo_up + _cmo_dn == 0) {_cmo = 0;}
|
||||
base.Add((TValue.t, _cmo), update, _NaN);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
using TradingPlatform.BusinessLayer;
|
||||
using System.Drawing;
|
||||
using QuanTAlib;
|
||||
using System;
|
||||
using TradingPlatform.BusinessLayer.Chart;
|
||||
|
||||
namespace QuanTAlib;
|
||||
|
||||
public abstract class QuanTAlib_Indicator : Indicator {
|
||||
protected TBars bars;
|
||||
protected IChartWindow mainWindow;
|
||||
protected Graphics graphics;
|
||||
protected int firstOnScreenBarIndex, lastOnScreenBarIndex;
|
||||
protected HistoricalData History;
|
||||
protected int HistPeriod;
|
||||
|
||||
protected override void OnInit() {
|
||||
base.OnInit();
|
||||
bars = new();
|
||||
var dur1 = this.HistoricalData.FromTime;
|
||||
var dur = this.HistoricalData.Period.Duration.TotalSeconds * (HistPeriod*4) ; //seconds of two periods
|
||||
|
||||
this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
|
||||
|
||||
for (int i = this.History.Count-1; i >= 0; i--) {
|
||||
|
||||
var rec = this.History[i, SeekOriginHistory.Begin];
|
||||
|
||||
bars.Add(rec.TimeLeft, rec[PriceType.Open],
|
||||
rec[PriceType.High], rec[PriceType.Low],
|
||||
rec[PriceType.Close], rec[PriceType.Volume]);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnUpdate(UpdateArgs args) {
|
||||
base.OnUpdate(args);
|
||||
bars.Add(Time(), GetPrice(PriceType.Open),
|
||||
GetPrice(PriceType.High),
|
||||
GetPrice(PriceType.Low),
|
||||
GetPrice(PriceType.Close),
|
||||
GetPrice(PriceType.Volume),
|
||||
update: !(args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar));
|
||||
}
|
||||
public override void OnPaintChart(PaintChartEventArgs args) {
|
||||
base.OnPaintChart(args);
|
||||
if (this.CurrentChart == null) return;
|
||||
graphics = args.Graphics;
|
||||
mainWindow = this.CurrentChart.MainWindow;
|
||||
|
||||
DateTime leftTime = mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left);
|
||||
DateTime rightTime = mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right);
|
||||
firstOnScreenBarIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(leftTime);
|
||||
lastOnScreenBarIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(rightTime));
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,10 @@ using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using TradingPlatform.BusinessLayer;
|
||||
using TradingPlatform.BusinessLayer.Chart;
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class JMA_chart : QuanTAlib_Indicator {
|
||||
public class JMA_chart : Indicator {
|
||||
#region Parameters
|
||||
|
||||
[InputParameter("Data source", 0, variants: new object[]
|
||||
@@ -31,6 +32,12 @@ public class JMA_chart : QuanTAlib_Indicator {
|
||||
private JMA_Series indicator;
|
||||
///////
|
||||
|
||||
protected TBars bars;
|
||||
protected IChartWindow mainWindow;
|
||||
protected Graphics graphics;
|
||||
protected int firstOnScreenBarIndex, lastOnScreenBarIndex;
|
||||
protected HistoricalData History;
|
||||
protected int HistPeriod;
|
||||
public JMA_chart() :base() {
|
||||
Name = "JMA - Jurik Moving Avg";
|
||||
Description = "Jurik Moving Average description";
|
||||
@@ -42,6 +49,21 @@ public class JMA_chart : QuanTAlib_Indicator {
|
||||
|
||||
protected override void OnInit() {
|
||||
base.OnInit();
|
||||
bars = new();
|
||||
var dur1 = this.HistoricalData.FromTime;
|
||||
var dur = this.HistoricalData.Period.Duration.TotalSeconds * (HistPeriod * 4); //seconds of two periods
|
||||
|
||||
this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
|
||||
|
||||
for (int i = this.History.Count - 1; i >= 0; i--) {
|
||||
|
||||
var rec = this.History[i, SeekOriginHistory.Begin];
|
||||
|
||||
bars.Add(rec.TimeLeft, rec[PriceType.Open],
|
||||
rec[PriceType.High], rec[PriceType.Low],
|
||||
rec[PriceType.Close], rec[PriceType.Volume]);
|
||||
}
|
||||
|
||||
indicator = new(source: bars.Select(DataSource), period: Period,
|
||||
phase: Jphase, vshort: Vshort, vlong: Vlong,
|
||||
useNaN: true);
|
||||
@@ -49,6 +71,26 @@ public class JMA_chart : QuanTAlib_Indicator {
|
||||
|
||||
protected override void OnUpdate(UpdateArgs args) {
|
||||
base.OnUpdate(args);
|
||||
bars.Add(Time(), GetPrice(PriceType.Open),
|
||||
GetPrice(PriceType.High),
|
||||
GetPrice(PriceType.Low),
|
||||
GetPrice(PriceType.Close),
|
||||
GetPrice(PriceType.Volume),
|
||||
update: !(args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar));
|
||||
|
||||
this.SetValue(indicator[^1].v, lineIndex: 0);
|
||||
}
|
||||
public override void OnPaintChart(PaintChartEventArgs args) {
|
||||
base.OnPaintChart(args);
|
||||
if (this.CurrentChart == null)
|
||||
return;
|
||||
graphics = args.Graphics;
|
||||
mainWindow = this.CurrentChart.MainWindow;
|
||||
|
||||
DateTime leftTime = mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left);
|
||||
DateTime rightTime = mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right);
|
||||
firstOnScreenBarIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(leftTime);
|
||||
lastOnScreenBarIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(rightTime));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ public class MovingAverage_chart : Indicator {
|
||||
|
||||
overunder = new(MA1, MA2);
|
||||
trades = new(MA1, MA2);
|
||||
equity = new(trades,prices: bars.Open,Long:LongTrades,Short:ShortTrades,Warmup:MA1Period+MA2Period);
|
||||
equity = new(trades,price: bars.Open,warmup:MA1Period+MA2Period);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(UpdateArgs args) {
|
||||
@@ -253,7 +253,7 @@ public class MovingAverage_chart : Indicator {
|
||||
}
|
||||
public override void OnPaintChart(PaintChartEventArgs args) {
|
||||
base.OnPaintChart(args);
|
||||
if (this.CurrentChart == null) return;
|
||||
if (this.CurrentChart == null) {return;}
|
||||
Graphics graphics = args.Graphics;
|
||||
var mainWindow = this.CurrentChart.MainWindow;
|
||||
int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
|
||||
|
||||
@@ -38,8 +38,8 @@ namespace SimpleMACross {
|
||||
}
|
||||
|
||||
protected override void OnRun() {
|
||||
if (this.CurrentAccount != null && this.CurrentAccount.State == BusinessObjectState.Fake) this.CurrentAccount = Core.Instance.GetAccount(this.CurrentAccount.CreateInfo());
|
||||
if (this.CurrentSymbol != null && this.CurrentSymbol.State == BusinessObjectState.Fake) this.CurrentSymbol = Core.Instance.GetSymbol(this.CurrentSymbol.CreateInfo());
|
||||
if (this.CurrentAccount != null && this.CurrentAccount.State == BusinessObjectState.Fake) {this.CurrentAccount = Core.Instance.GetAccount(this.CurrentAccount.CreateInfo());}
|
||||
if (this.CurrentSymbol != null && this.CurrentSymbol.State == BusinessObjectState.Fake) {this.CurrentSymbol = Core.Instance.GetSymbol(this.CurrentSymbol.CreateInfo());}
|
||||
if (this.CurrentSymbol == null || this.CurrentAccount == null || this.CurrentSymbol.ConnectionId != this.CurrentAccount.ConnectionId) {
|
||||
this.Log("Incorrect input parameters... Symbol or Account are not specified or they have different connectionID.", StrategyLoggingLevel.Error);
|
||||
return; }
|
||||
@@ -59,12 +59,12 @@ namespace SimpleMACross {
|
||||
|
||||
private void OnUpdate() {
|
||||
bool update = hdm.Last().TimeLeft - prev_time < this.period.Duration ? true : false;
|
||||
if (!update) prev_time = hdm.Last().TimeLeft;
|
||||
if (!update) {prev_time = hdm.Last().TimeLeft;}
|
||||
|
||||
bars.Add(hdm.Last().TimeLeft, hdm.Last()[PriceType.Open], hdm.Last()[PriceType.High],
|
||||
hdm.Last()[PriceType.Low], hdm.Last()[PriceType.Close], hdm.Last()[PriceType.Volume], update);
|
||||
|
||||
if (!update) this.LogInfo($"{bars.Close.Last().t} OHLC4:{(double)bars.OHLC4}");
|
||||
if (!update) {this.LogInfo($"{bars.Close.Last().t} OHLC4:{(double)bars.OHLC4}");}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user