diff --git a/.github/TradingPlatform.BusinessLayer.dll b/.github/TradingPlatform.BusinessLayer.dll index 0a324bcb..d1cca1dc 100644 Binary files a/.github/TradingPlatform.BusinessLayer.dll and b/.github/TradingPlatform.BusinessLayer.dll differ diff --git a/.github/TradingPlatform.BusinessLayer.xml b/.github/TradingPlatform.BusinessLayer.xml index 47ebf0f0..60fa288b 100644 --- a/.github/TradingPlatform.BusinessLayer.xml +++ b/.github/TradingPlatform.BusinessLayer.xml @@ -377,21 +377,6 @@ Mediates a history meta data with available data types and intervals on vendor side - - - History data types - - - - - History intervals - - - - - History intervals - - Asset id bearer @@ -1948,7 +1933,7 @@ - + Gets historical data according to aggregation and other parameters @@ -2965,21 +2950,11 @@ Gets HistoricalData symbol - - - Gets HistoricalData Period - - Gets HistoricalData aggregation - - - Gets HistoricalData history type - - Gets HistoricalData left time boundary diff --git a/.github/workflows/Publish.yml b/.github/workflows/Publish.yml index ada29549..edd100b9 100644 --- a/.github/workflows/Publish.yml +++ b/.github/workflows/Publish.yml @@ -43,15 +43,28 @@ jobs: - name: SonarCloud Scanner Start env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: | + if [[ ${{ github.event_name }} == 'pull_request' ]]; then + PR_PARAMS="/d:sonar.pullrequest.key=${{ github.event.pull_request.number }} \ + /d:sonar.pullrequest.branch=${{ github.head_ref }} \ + /d:sonar.pullrequest.base=${{ github.base_ref }}" + elif [[ ${{ github.event_name }} == 'push' ]]; then + BRANCH_PARAMS="/d:sonar.branch.name=${{ github.ref_name }}" + else + BRANCH_PARAMS="/d:sonar.branch.name=${{ github.ref_name }}" + fi + dotnet sonarscanner begin \ /k:"mihakralj_QuanTAlib" \ /o:"mihakralj" \ /d:sonar.token="${{ secrets.SONAR_TOKEN }}" \ /d:sonar.host.url="https://sonarcloud.io" \ /d:sonar.cs.dotcover.reportsPaths=dotcover* \ - /d:sonar.scanner.scanAll=false + /d:sonar.scanner.scanAll=false \ + /d:sonar.scm.provider=git \ + $PR_PARAMS $BRANCH_PARAMS - name: Build run: | @@ -216,7 +229,10 @@ jobs: build_publish: needs: [SonarCloud, Code_Coverage, CodeQL, Codacy_Scan, SecurityCodeScan] - if: success() + if: | + success() && + (github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) || + github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest steps: - name: Checkout repository diff --git a/QuanTAlib.sln b/QuanTAlib.sln index bd69454d..068fcd79 100644 --- a/QuanTAlib.sln +++ b/QuanTAlib.sln @@ -1,5 +1,4 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 @@ -7,15 +6,15 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "quantalib", "lib\quantalib. EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "quantower", "quantower", "{1B9AC248-76F8-44DD-958D-F1DC08EE1E87}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Statistics", "quantower\Statistics\Statistics.csproj", "{2E9427C7-144F-488E-A29D-789ACC1C32AE}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Statistics", "quantower\Statistics\_Statistics.csproj", "{2E9427C7-144F-488E-A29D-789ACC1C32AE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Averages", "quantower\Averages\Averages.csproj", "{6BE10C39-4127-446C-818B-7976FCDD51D5}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Averages", "quantower\Averages\_Averages.csproj", "{6BE10C39-4127-446C-818B-7976FCDD51D5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volatility", "quantower\Volatility\Volatility.csproj", "{B7DC44F7-D3A3-4C70-9025-513E0182B646}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volatility", "quantower\Volatility\_Volatility.csproj", "{B7DC44F7-D3A3-4C70-9025-513E0182B646}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntheticVendor", "SyntheticVendor\SyntheticVendor.csproj", "{1CF111D9-33E6-4A11-8FEC-F23300A78D15}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{E204F173-5840-4AA3-BED1-98C8D2F813E3}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{2D97C971-20BF-40DB-94AA-3279F787D3CB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -41,15 +40,16 @@ Global {B7DC44F7-D3A3-4C70-9025-513E0182B646}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B7DC44F7-D3A3-4C70-9025-513E0182B646}.Debug|Any CPU.Build.0 = Debug|Any CPU {B7DC44F7-D3A3-4C70-9025-513E0182B646}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B7DC44F7-D3A3-4C70-9025-513E0182B646}.Release|Any CPU.Build.0 = Release|Any CPU - {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Release|Any CPU.Build.0 = Release|Any CPU - {E204F173-5840-4AA3-BED1-98C8D2F813E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E204F173-5840-4AA3-BED1-98C8D2F813E3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E204F173-5840-4AA3-BED1-98C8D2F813E3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E204F173-5840-4AA3-BED1-98C8D2F813E3}.Release|Any CPU.Build.0 = Release|Any CPU + {B7DC44F7-D3A3-4C70-9025-513E0182B646}.Release | Any CPU.ActiveCfg = Release | Any CPU + {B7DC44F7-D3A3-4C70-9025-513E0182B646}.Release | Any CPU.Build.0 = Release | Any CPU + {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Debug | Any CPU.ActiveCfg = Debug | Any CPU + {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Debug | Any CPU.Build.0 = Debug | Any CPU + {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Release | Any CPU.ActiveCfg = Release | Any CPU + {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Release | Any CPU.Build.0 = Release | Any CPU + {2D97C971-20BF-40DB-94AA-3279F787D3CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D97C971-20BF-40DB-94AA-3279F787D3CB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D97C971-20BF-40DB-94AA-3279F787D3CB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D97C971-20BF-40DB-94AA-3279F787D3CB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {2E9427C7-144F-488E-A29D-789ACC1C32AE} = {1B9AC248-76F8-44DD-958D-F1DC08EE1E87} diff --git a/SyntheticVendor/SyntheticVendor.cs b/SyntheticVendor/SyntheticVendor.cs index 60c2118a..913041a4 100644 --- a/SyntheticVendor/SyntheticVendor.cs +++ b/SyntheticVendor/SyntheticVendor.cs @@ -5,10 +5,7 @@ using TradingPlatform.BusinessLayer; using TradingPlatform.BusinessLayer.Integration; using System.Diagnostics.CodeAnalysis; - namespace SyntheticVendorNamespace; -[SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")] - public class SyntheticVendor : Vendor { @@ -101,6 +98,25 @@ public class SyntheticVendor : Vendor } + public static VendorMetaData GetVendorMetaData() + { + return new VendorMetaData() + { + VendorName = "Synthetic Vendor", + VendorDescription = "A synthetic vendor for testing and demonstration purposes", + GetDefaultConnections = () => + { + var defaultConnection = Vendor.CreateDefaultConnectionInfo( + "Synthetic Connection", + "Synthetic Vendor", + "", // Replace with actual path if you have a logo + allowCreateCustomConnections: true + ); + return new List { defaultConnection }; + } + }; + } + private MessageSymbol CreateMessageSymbol( string id, string name, @@ -131,24 +147,7 @@ public class SyntheticVendor : Vendor return messageSymbol; } - public static VendorMetaData GetVendorMetaData() - { - return new VendorMetaData() - { - VendorName = "Synthetic Vendor", - VendorDescription = "A synthetic vendor for testing and demonstration purposes", - GetDefaultConnections = () => - { - var defaultConnection = Vendor.CreateDefaultConnectionInfo( - "Synthetic Connection", - "Synthetic Vendor", - "", // Replace with actual path if you have a logo - allowCreateCustomConnections: true - ); - return new List { defaultConnection }; - } - }; - } + private MessageSymbol CreateMessageSymbol(string id, string name, string exchangeId, string assetId, SymbolType type) @@ -226,20 +225,6 @@ public class SyntheticVendor : Vendor } - - - public override void OnConnected(CancellationToken token) - { - // This method is called after a successful connection - // You can initialize resources or start any necessary processes here - base.OnConnected(token); - - // For example, you might want to push some initial messages or data - // PushMessage(new MessageVendorEvent("SyntheticVendor connected successfully")); - } - - - public override IList GetExchanges(CancellationToken token) { return exchanges; @@ -310,7 +295,6 @@ public class SyntheticVendor : Vendor { switch (symbolId) { - //case "W0": return GenerateConstant; case "W1": return GenerateSpike; case "W2": return GenerateDiracDelta; case "W3": return GenerateSquareWave; @@ -333,36 +317,52 @@ public class SyntheticVendor : Vendor } } +/* public override HistoryMetadata GetHistoryMetadata(CancellationToken cancellationToken) { - return new HistoryMetadata() + return new HistoryMetadata { - AllowedHistoryTypes = new HistoryType[] + AllowedAggregations = new string[] { "Time", "Tick" }, + AllowedPeriodsHistoryAggregationTime = new Period[] { - HistoryType.Bid, - HistoryType.Ask, - HistoryType.Midpoint, - HistoryType.Last, - HistoryType.BidAsk, - HistoryType.Mark, + Period.SECOND1, Period.SECOND5, Period.SECOND10, Period.SECOND15, Period.SECOND30, + Period.MIN1, Period.MIN2, Period.MIN3, Period.MIN4, Period.MIN5, + Period.MIN10, Period.MIN15, Period.MIN30, + Period.HOUR1, Period.HOUR2, Period.HOUR3, Period.HOUR4, + Period.HOUR6, Period.HOUR8, Period.HOUR12, + Period.DAY1, + Period.WEEK1, + Period.MONTH1, + Period.YEAR1 }, - AllowedPeriods = new Period[] + AllowedBasePeriodsHistoryAggregationTime = new BasePeriod[] { - Period.TICK1, - Period.SECOND1, Period.SECOND5, Period.SECOND10, Period.SECOND15, Period.SECOND30, - Period.MIN1, Period.MIN2, Period.MIN3, Period.MIN4, Period.MIN5, - Period.MIN10, Period.MIN15, Period.MIN30, - Period.HOUR1, Period.HOUR2, Period.HOUR3, Period.HOUR4, - Period.HOUR6, Period.HOUR8, Period.HOUR12, - Period.DAY1, - Period.WEEK1, - Period.MONTH1, - Period.YEAR1 + BasePeriod.Second, BasePeriod.Minute, BasePeriod.Hour, BasePeriod.Day, BasePeriod.Week, BasePeriod.Month, BasePeriod.Year }, - UseHistoryLocalCache = false + AllowedHistoryTypesHistoryAggregationTime = new HistoryType[] + { + HistoryType.Bid, + HistoryType.Ask, + HistoryType.Midpoint, + HistoryType.Last, + HistoryType.BidAsk, + HistoryType.Mark + }, + AllowedHistoryTypesHistoryAggregationTick = new HistoryType[] + { + HistoryType.Bid, + HistoryType.Ask, + HistoryType.Midpoint, + HistoryType.Last, + HistoryType.BidAsk, + HistoryType.Mark + }, + DegreeOfParallelism = 1, + UseHistoryLocalCache = false, + BuildUncompletedBars = true }; } - +*/ /*******************************************************************************************************************************************/ /*******************************************************************************************************************************************/ @@ -418,18 +418,6 @@ public class SyntheticVendor : Vendor - - private static readonly double[] distributionValues = new double[] - { - 0.010, // Extreme left tail - 0.050, // Left tail - 0.200, // Left of center - 0.480, // Center (peak) - 0.200, // Right of center - 0.050, // Right tail - 0.010 // Extreme right tail - }; - private HistoryItemBar GenerateDiracDelta(DateTime time, TimeSpan slice) { // Ensure we're working with UTC time @@ -972,7 +960,7 @@ public class SyntheticVendor : Vendor private const int NumOctaves = 6; - private double[] pinkNoiseState = new double[NumOctaves]; + private readonly double[] pinkNoiseState = new double[NumOctaves]; private double GeneratePinkNoiseValue() { double total = 0; @@ -1033,8 +1021,8 @@ public class SyntheticVendor : Vendor private double GBMLastClose = 100; // Starting price - private double GBMMu = 0.05; // Annual drift - private double GBMSigma = 0.2; // Annual volatility + private readonly double GBMMu = 0.05; // Annual drift + private readonly double GBMSigma = 0.2; // Annual volatility private HistoryItemBar GenerateGBM(DateTime time, TimeSpan slice) { @@ -1081,9 +1069,9 @@ public class SyntheticVendor : Vendor } private double FBMLastClose = 100; // Starting price - private double FBMHurst = 0.85; // Hurst parameter (0.5 < H < 1 for persistent fBm) - private double FBMSigma = 0.25; // Volatility parameter - private double FBMDrift = 0.001; // drift + private readonly double FBMHurst = 0.85; // Hurst parameter (0.5 < H < 1 for persistent fBm) + private readonly double FBMSigma = 0.25; // Volatility parameter + private readonly double FBMDrift = 0.001; // drift private HistoryItemBar GenerateFBM(DateTime time, TimeSpan slice) { diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index da2d0d68..18f54f05 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -37,7 +37,10 @@ - + + + + diff --git a/Tests/test_quantower.cs b/Tests/test_quantower.cs index fc7e9058..a82e0cbb 100644 --- a/Tests/test_quantower.cs +++ b/Tests/test_quantower.cs @@ -1,7 +1,13 @@ +extern alias volatility; +extern alias averages; +extern alias statistics; + using Xunit; -using System; using System.Reflection; using TradingPlatform.BusinessLayer; +using statistics::QuanTAlib; +using averages::QuanTAlib; +using volatility::QuanTAlib; namespace QuanTAlib { @@ -83,7 +89,7 @@ namespace QuanTAlib [Fact] public void Slope() => TestIndicator("slope"); [Fact] public void Stddev() => TestIndicator("stddev"); [Fact] public void Variance() => TestIndicator("variance"); - [Fact] public void Zscore() => TestIndicator("zScore"); + [Fact] public void Zscore() => TestIndicator("zScore"); // Volatility Indicators [Fact] public void Atr() => TestIndicator("atr"); diff --git a/quantower/AbstractIndicatorBase.cs b/quantower/AbstractIndicatorBase.cs deleted file mode 100644 index 0f650904..00000000 --- a/quantower/AbstractIndicatorBase.cs +++ /dev/null @@ -1,148 +0,0 @@ -using System.Drawing; -using TradingPlatform.BusinessLayer; -using TradingPlatform.BusinessLayer.Chart; -using System.Runtime.CompilerServices; -using System.Drawing.Drawing2D; -namespace QuanTAlib; - -#pragma warning disable CA1416 // Validate platform compatibility -public abstract class AbstractIndicatorBase : Indicator -{ - - [InputParameter("Data source", sortIndex: 18, variants: new object[]{ - "Close", PriceType.Close, - "Open", PriceType.Open, - "High", PriceType.High, - "Low", PriceType.Low, - "Typical", PriceType.Typical, - "Median", PriceType.Median, - "Weighted", PriceType.Weighted - })] - public PriceType SourcePrice { get; set; } = PriceType.Close; - - [InputParameter(name: "Line smoothing", sortIndex: 19, minimum: 0.0, maximum: 1.0, increment: 0.1, decimalPlaces: 2)] - public double Tension = 0.2; - - [InputParameter("Show cold values", sortIndex: 20)] - public bool ShowColdValues { get; set; } = true; - - // LineSeries.LineSeries(string, Color, int, LineStyle)' - - protected LineSeries? Series; - protected abstract AbstractBase MovingAverage { get; } - - protected AbstractIndicatorBase() : base() - { - OnBackGround = true; - SeparateWindow = false; - Series = new(name: $"Name", color: Color.Orange, width: 2, style: LineStyle.Solid); - AddLineSeries(Series); - - InitIndicator(); - } - - protected virtual void InitIndicator() - { - } - - protected override void OnInit() - { - InitIndicator(); - base.OnInit(); - } - - protected override void OnUpdate(UpdateArgs args) - { - base.OnUpdate(args); - bool isNew = this.HistoricalData.Aggregation.GetPeriod == Period.TICK1 - ? args.Reason == UpdateReason.NewTick || args.Reason == UpdateReason.HistoricalBar - : args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar; - double price = GetPrice(SourcePrice); - - TValue input = new TValue(Time(), price, isNew); - TValue result = MovingAverage.Calc(input); - - Series!.SetMarker(0, Color.Transparent); - Series.SetValue(result.Value); - - } - - public override void OnPaintChart(PaintChartEventArgs args) - { - base.OnPaintChart(args); - List allPoints = new List(); - if (CurrentChart == null) return; - - Graphics gr = args.Graphics; - var mainWindow = CurrentChart.MainWindow; - var converter = mainWindow.CoordinatesConverter; - var clientRect = mainWindow.ClientRectangle; - - gr.SetClip(clientRect); - DateTime leftTime = new[] { converter.GetTime(clientRect.Left), Time(this.Count - 1) }.Max(); - DateTime rightTime = new[] { converter.GetTime(clientRect.Right), Time(0) }.Min(); - - int leftIndex = (int)HistoricalData.GetIndexByTime(leftTime.Ticks) + 1; - int rightIndex = (int)HistoricalData.GetIndexByTime(rightTime.Ticks); - - for (int i = rightIndex; i < leftIndex; i++) - { - int barX = (int)converter.GetChartX(Time(i)); - int barY = (int)converter.GetChartY(Series![i]); - int halfBarWidth = CurrentChart.BarsWidth / 2; - Point point = new Point(barX + halfBarWidth, barY); - allPoints.Add(point); - } - - if (allPoints.Count > 1) - { - DrawSmoothCombinedCurve(gr, allPoints, this.Count - MovingAverage.WarmupPeriod - rightIndex); - } - } - - private void DrawSmoothCombinedCurve(Graphics gr, List allPoints, int hotCount) - { - if (allPoints.Count < 2) return; - - using (Pen defaultPen = new(Series!.Color, Series.Width) { DashStyle = ConvertLineStyleToDashStyle(Series.Style) }) - using (Pen coldPen = new(Series!.Color, Series.Width) { DashStyle = DashStyle.Dot }) - { - // Draw the hot part - if (hotCount > 0) - { - var hotPoints = allPoints.Take(Math.Min(hotCount + 1, allPoints.Count)).ToArray(); - gr.DrawCurve(defaultPen, hotPoints, 0, hotPoints.Length - 1, (float)Tension); - } - - // Draw the cold part - if (ShowColdValues && hotCount < allPoints.Count) - { - var coldPoints = allPoints.Skip(Math.Max(0, hotCount)).ToArray(); - gr.DrawCurve(coldPen, coldPoints, 0, coldPoints.Length - 1, (float)Tension); - } - } - } - - protected void DrawText(Graphics gr, string text, Rectangle clientRect) - { - Font font = new Font("Inter", 8); - SizeF textSize = gr.MeasureString(text, font); - RectangleF textRect = new RectangleF(clientRect.Left + 5, - clientRect.Bottom - textSize.Height - 10, - textSize.Width + 10, textSize.Height + 10); - gr.FillRectangle(SystemBrushes.ControlDarkDark, textRect); - gr.DrawString(text, font, Brushes.White, new PointF(textRect.X + 6, textRect.Y + 5)); - } - - private DashStyle ConvertLineStyleToDashStyle(LineStyle lineStyle) - { - return lineStyle switch - { - LineStyle.Solid => DashStyle.Solid, - LineStyle.Dash => DashStyle.Dash, - LineStyle.Dot => DashStyle.Dot, - LineStyle.DashDot => DashStyle.DashDot, - _ => DashStyle.Solid, - }; - } -} \ No newline at end of file diff --git a/quantower/Averages/AfirmaIndicator.cs b/quantower/Averages/AfirmaIndicator.cs index 3163b30b..c3f3fc75 100644 --- a/quantower/Averages/AfirmaIndicator.cs +++ b/quantower/Averages/AfirmaIndicator.cs @@ -1,7 +1,9 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class AfirmaIndicator : IndicatorBase +public class AfirmaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Taps (number of weights)", sortIndex: 1, 1, 2000, 1, 0)] public int Taps { get; set; } = 6; @@ -11,27 +13,59 @@ public class AfirmaIndicator : IndicatorBase [InputParameter("Window Type", sortIndex: 3, variants: [ "Rectangular", Afirma.WindowType.Rectangular, - "Hanning", Afirma.WindowType.Hanning1, - "Hamming", Afirma.WindowType.Hanning2, - "Blackman", Afirma.WindowType.Blackman, - "Blackman-Harris", Afirma.WindowType.BlackmanHarris + "Hanning", Afirma.WindowType.Hanning1, + "Hamming", Afirma.WindowType.Hanning2, + "Blackman", Afirma.WindowType.Blackman, + "Blackman-Harris", Afirma.WindowType.BlackmanHarris ])] public Afirma.WindowType Window { get; set; } = Afirma.WindowType.Hanning1; + [InputParameter("Data source", sortIndex: 4, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + private Afirma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"AFIRMA {Taps}:{Periods}:{Window} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods + Taps; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public AfirmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "AFIRMA - Adaptive Finite Impulse Response Moving Average"; Description = "Adaptive Finite Impulse Response Moving Average with ARMA component"; + Series = new(name: $"AFIRMA {Taps}:{Periods}:{Window}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - base.InitIndicator(); ma = new Afirma(periods: Periods, taps: Taps, window: Window); + SourceName = Source.ToString(); + base.OnInit(); } + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"AFIRMA {Taps}:{Periods}:{Window}:{SourceName}"; } + diff --git a/quantower/Averages/AlmaIndicator.cs b/quantower/Averages/AlmaIndicator.cs index 7843a0c5..bc8781d1 100644 --- a/quantower/Averages/AlmaIndicator.cs +++ b/quantower/Averages/AlmaIndicator.cs @@ -1,30 +1,64 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class AlmaIndicator : IndicatorBase +public class AlmaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] public int Period { get; set; } = 10; - [InputParameter("Offset", sortIndex: 5)] + [InputParameter("Offset", sortIndex: 2)] public double Offset { get; set; } = 0.85; - [InputParameter("Sigma", sortIndex: 6)] + [InputParameter("Sigma", sortIndex: 3)] public double Sigma { get; set; } = 6.0; - private Alma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"ALMA {Period} : {Offset:F2} : {Sigma:F0} : {SourceName}"; - public AlmaIndicator() : base() + [InputParameter("Data source", sortIndex: 4, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + + private Alma? ma; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Period; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public AlmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "ALMA - Arnaud Legoux Moving Average"; Description = "Arnaud Legoux Moving Average"; - + Series = new(name: $"ALMA {Period}:{Offset:F2}:{Sigma:F0}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - base.InitIndicator(); ma = new Alma(period: Period, offset: Offset, sigma: Sigma); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"ALMA {Period}:{Offset:F2}:{Sigma:F0}:{SourceName}"; } diff --git a/quantower/Averages/DemaIndicator.cs b/quantower/Averages/DemaIndicator.cs index f11d5ce4..d7777af1 100644 --- a/quantower/Averages/DemaIndicator.cs +++ b/quantower/Averages/DemaIndicator.cs @@ -1,23 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class DemaIndicator : IndicatorBase +public class DemaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] public int Period { get; set; } = 10; - private Dema? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"DEMA {Period} : {SourceName}"; - public DemaIndicator() : base() + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + + private Dema? ma; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Period; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public DemaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "DEMA - Double Exponential Moving Average"; Description = "A faster-responding moving average that reduces lag by applying the EMA twice."; + Series = new(name: $"DEMA {Period}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - base.InitIndicator(); ma = new Dema(period: Period); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"DEMA {Period}:{SourceName}"; } diff --git a/quantower/Averages/DsmaIndicator.cs b/quantower/Averages/DsmaIndicator.cs index cc14789d..b860bb62 100644 --- a/quantower/Averages/DsmaIndicator.cs +++ b/quantower/Averages/DsmaIndicator.cs @@ -1,27 +1,63 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class DsmaIndicator : IndicatorBase +public class DsmaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] public int Period { get; set; } = 10; + [InputParameter("Scale factor", sortIndex: 2, minimum: 0.01, maximum: 1.0, increment: 0.01, decimalPlaces: 2)] public double Scale { get; set; } = 0.5; - private Dsma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"DSMA {Period} : {Scale:F2} : {SourceName}"; + [InputParameter("Data source", sortIndex: 3, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; - public DsmaIndicator() : base() + private Dsma? ma; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths { get; private set; } + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public DsmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "DSMA - Deviation Scaled Moving Average"; Description = "A moving average that adjusts its responsiveness based on price deviations from the mean."; + Series = new(name: $"DSMA {Period}:{Scale:F2}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { ma = new Dsma(Period, Scale); MinHistoryDepths = ma.WarmupPeriod; - base.InitIndicator(); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"DSMA {Period}:{Scale:F2}:{SourceName}"; } + diff --git a/quantower/Averages/DwmaIndicator.cs b/quantower/Averages/DwmaIndicator.cs index a1f3be2b..a78292ea 100644 --- a/quantower/Averages/DwmaIndicator.cs +++ b/quantower/Averages/DwmaIndicator.cs @@ -1,24 +1,59 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class DwmaIndicator : IndicatorBase +public class DwmaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] public int Period { get; set; } = 10; - private Dwma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"DWMA {Period} : {SourceName}"; + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; - public DwmaIndicator() : base() + private Dwma? ma; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Period; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public DwmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "DWMA - Double Weighted Moving Average"; Description = "A moving average that applies double weighting to recent prices for increased responsiveness."; + Series = new(name: $"DWMA {Period}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { ma = new Dwma(Period); - base.InitIndicator(); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"DWMA {Period}:{SourceName}"; } + diff --git a/quantower/Averages/EmaIndicator.cs b/quantower/Averages/EmaIndicator.cs index 5d8fc937..657388d8 100644 --- a/quantower/Averages/EmaIndicator.cs +++ b/quantower/Averages/EmaIndicator.cs @@ -1,27 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class EmaIndicator : IndicatorBase +public class EmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; - [InputParameter("Use SMA for warmup", sortIndex: 5)] - public bool UseSma { get; set; } = false; + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Ema? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"EMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public EmaIndicator() : base() + public EmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "EMA - Exponential Moving Average"; - Description = "Moving average that gives more weight to recent prices, reducing lag in trend following."; + Description = "Exponential Moving Average"; + Series = new(name: $"EMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - base.InitIndicator(); - ma = new Ema(period: Period, useSma: UseSma); + ma = new Ema(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"EMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/EpmaIndicator.cs b/quantower/Averages/EpmaIndicator.cs index 5fee343d..e5fdad82 100644 --- a/quantower/Averages/EpmaIndicator.cs +++ b/quantower/Averages/EpmaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class EpmaIndicator : IndicatorBase +public class EpmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Epma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"EPMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public EpmaIndicator() : base() + public EpmaIndicator() { - Name = "EPMA - Endpoint Moving Average"; - Description = "Moving average that emphasizes the most recent data point, useful for identifying trend changes."; + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); + Name = "EPMA - Exponential Percentage Moving Average"; + Description = "Exponential Percentage Moving Average"; + Series = new(name: $"EPMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - base.InitIndicator(); - ma = new Epma(period: Period); + ma = new Epma(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"EPMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/FramaIndicator.cs b/quantower/Averages/FramaIndicator.cs index 9a1959ca..df848cd8 100644 --- a/quantower/Averages/FramaIndicator.cs +++ b/quantower/Averages/FramaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class FramaIndicator : IndicatorBase +public class FramaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Frama? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"FRAMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods * 2; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public FramaIndicator() : base() + public FramaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "FRAMA - Fractal Adaptive Moving Average"; - Description = "Adaptive moving average that adjusts its smoothing based on market fractal dimension."; + Description = "Fractal Adaptive Moving Average"; + Series = new(name: $"FRAMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Frama(Period); - base.InitIndicator(); + ma = new Frama(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"FRAMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/FwmaIndicator.cs b/quantower/Averages/FwmaIndicator.cs index 4dee3a20..4a9af703 100644 --- a/quantower/Averages/FwmaIndicator.cs +++ b/quantower/Averages/FwmaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class FwmaIndicator : IndicatorBase +public class FwmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Fwma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"FWMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public FwmaIndicator() : base() + public FwmaIndicator() { - Name = "FWMA - Fibonacci-Weighted Moving Average"; - Description = "Moving average that uses Fibonacci sequence for weighting, emphasizing recent and key historical prices."; + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); + Name = "FWMA - Fibonacci Weighted Moving Average"; + Description = "Fibonacci Weighted Moving Average"; + Series = new(name: $"FWMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Fwma(Period); - base.InitIndicator(); + ma = new Fwma(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"FWMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/GmaIndicator.cs b/quantower/Averages/GmaIndicator.cs index cbbd2ad0..6bc0453f 100644 --- a/quantower/Averages/GmaIndicator.cs +++ b/quantower/Averages/GmaIndicator.cs @@ -1,24 +1,61 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class GmaIndicator : IndicatorBase +public class GmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Sigma", sortIndex: 2, 0.1, 10, 0.1, 1)] + public double Sigma { get; set; } = 1.0; + + [InputParameter("Data source", sortIndex: 3, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Gma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"GMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public GmaIndicator() : base() + public GmaIndicator() { - Name = "GMA - Gaussian-Weighted Moving Average"; - Description = "Moving average using Gaussian distribution for weighting, balancing recent and historical data."; + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); + Name = "GMA - Gaussian Moving Average"; + Description = "Gaussian Moving Average"; + Series = new(name: $"GMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Gma(Period); - base.InitIndicator(); + ma = new Gma(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"GMA {Periods}:{Sigma}:{SourceName}"; } diff --git a/quantower/Averages/HmaIndicator.cs b/quantower/Averages/HmaIndicator.cs index e255579c..842f327f 100644 --- a/quantower/Averages/HmaIndicator.cs +++ b/quantower/Averages/HmaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class HmaIndicator : IndicatorBase +public class HmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Hma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"HMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods + (int)Math.Sqrt(Periods) - 1; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public HmaIndicator() : base() + public HmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "HMA - Hull Moving Average"; - Description = "Responsive moving average that reduces lag while maintaining smoothness in price action."; + Description = "Hull Moving Average"; + Series = new(name: $"HMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Hma(Period); - base.InitIndicator(); + ma = new Hma(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"HMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/HtitIndicator.cs b/quantower/Averages/HtitIndicator.cs index b619134f..bf1b1f8a 100644 --- a/quantower/Averages/HtitIndicator.cs +++ b/quantower/Averages/HtitIndicator.cs @@ -1,22 +1,55 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class HtitIndicator : IndicatorBase +public class HtitIndicator : Indicator, IWatchlistIndicator { - private Htit? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"HTIT : {SourceName}"; + [InputParameter("Data source", sortIndex: 1, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; - public HtitIndicator() : base() + private Htit? ma; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => 12; // Based on WarmupPeriod in Htit + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public HtitIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "HTIT - Hilbert Transform Instantaneous Trendline"; - Description = "Uses Hilbert Transform to identify the dominant cycle and generate a smooth, lag-free trendline."; + Description = "Hilbert Transform Instantaneous Trendline (Note: This indicator may not be fully functional)"; + Series = new(name: "HTIT", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { ma = new Htit(); - MinHistoryDepths = ma.WarmupPeriod; - base.InitIndicator(); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"HTIT:{SourceName}"; } diff --git a/quantower/Averages/HwmaIndicator.cs b/quantower/Averages/HwmaIndicator.cs index 4c36f17a..fd76600a 100644 --- a/quantower/Averages/HwmaIndicator.cs +++ b/quantower/Averages/HwmaIndicator.cs @@ -1,30 +1,74 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class HwmaIndicator : IndicatorBase +public class HwmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("nA - smoothed series", sortIndex: 5, minimum: 0.0, maximum: 1.0, increment: 0.1, decimalPlaces: 2)] - public double nA { get; set; } = 0.18; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; - [InputParameter("nB - assess the trend (from 0 to 1)", sortIndex: 6, minimum: 0.0, maximum: 1.0, increment: 0.1, decimalPlaces: 2)] - public double nB { get; set; } = 0.1; + [InputParameter("nA", sortIndex: 2, 0, 1, 0.01, 2)] + public double NA { get; set; } = 0; - [InputParameter("nC - assess seasonality (from 0 to 1)", sortIndex: 7, minimum: 0.0, maximum: 1.0, increment: 0.1, decimalPlaces: 2)] - public double nC { get; set; } = 0.1; + [InputParameter("nB", sortIndex: 3, 0, 1, 0.01, 2)] + public double NB { get; set; } = 0; + + [InputParameter("nC", sortIndex: 4, 0, 1, 0.01, 2)] + public double NC { get; set; } = 0; + + [InputParameter("Data source", sortIndex: 5, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Hwma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"HWMA {nA:F2} : {nB:F2} : {nC:F2} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public HwmaIndicator() : base() + public HwmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "HWMA - Holt-Winter Moving Average"; - Description = "Triple exponential moving average that accounts for level, trend, and seasonal components."; + Description = "Holt-Winter Moving Average"; + Series = new(name: $"HWMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Hwma(nA: nA, nB: nB, nC: nC); - base.InitIndicator(); + if (NA == 0 && NB == 0 && NC == 0) + { + ma = new Hwma(Periods); + } + else + { + ma = new Hwma(Periods, NA, NB, NC); + } + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"HWMA {Periods}:{NA}:{NB}:{NC}:{SourceName}"; } diff --git a/quantower/Averages/JmaIndicator.cs b/quantower/Averages/JmaIndicator.cs index a80f9fc7..777ec8ee 100644 --- a/quantower/Averages/JmaIndicator.cs +++ b/quantower/Averages/JmaIndicator.cs @@ -1,26 +1,64 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class JmaIndicator : IndicatorBase +public class JmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; [InputParameter("Phase", sortIndex: 2, -100, 100, 1, 0)] - public int Phase { get; set; } = 0; + public double Phase { get; set; } = 0; + + [InputParameter("VShort", sortIndex: 3, 1, 100, 1, 0)] + public int VShort { get; set; } = 10; + + [InputParameter("Data source", sortIndex: 4, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + private Jma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"JMA {Period} : {Phase} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods * 2; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public JmaIndicator() : base() + public JmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "JMA - Jurik Moving Average"; - Description = "Adaptive moving average with reduced lag and noise, adjustable smoothness and phase shift."; + Description = "Jurik Moving Average (Note: This indicator may have consistency issues)"; + Series = new(name: $"JMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Jma(period: Period, phase: (double)Phase); - base.InitIndicator(); + ma = new Jma(Periods, Phase, VShort); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"JMA {Periods}:{Phase}:{VShort}:{SourceName}"; } diff --git a/quantower/Averages/KamaIndicator.cs b/quantower/Averages/KamaIndicator.cs index 028ca796..c6ba1abb 100644 --- a/quantower/Averages/KamaIndicator.cs +++ b/quantower/Averages/KamaIndicator.cs @@ -1,28 +1,64 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class KamaIndicator : IndicatorBase +public class KamaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; - [InputParameter("Fast", sortIndex: 2, 1, 2000, 1, 0)] + [InputParameter("Fast", sortIndex: 2, 1, 100, 1, 0)] public int Fast { get; set; } = 2; - [InputParameter("Slow", sortIndex: 3, 1, 2000, 1, 0)] + + [InputParameter("Slow", sortIndex: 3, 1, 100, 1, 0)] public int Slow { get; set; } = 30; + + [InputParameter("Data source", sortIndex: 4, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + private Kama? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"KAMA {Period} : {Fast} : {Slow} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public KamaIndicator() : base() + public KamaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "KAMA - Kaufman's Adaptive Moving Average"; - Description = "Adaptive moving average that adjusts to market volatility, reducing lag in trending markets."; + Description = "Kaufman's Adaptive Moving Average"; + Series = new(name: $"KAMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Kama(Period, Fast, Slow); - base.InitIndicator(); + ma = new Kama(Periods, Fast, Slow); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"KAMA {Periods}:{Fast}:{Slow}:{SourceName}"; } diff --git a/quantower/Averages/LtmaIndicator.cs b/quantower/Averages/LtmaIndicator.cs index ebf29dc5..9682a3fe 100644 --- a/quantower/Averages/LtmaIndicator.cs +++ b/quantower/Averages/LtmaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class LtmaIndicator : IndicatorBase +public class LtmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Gamma", sortIndex: 1, 0, 1, 0.01, 2)] - public double Gamma { get; set; } = 0.10; + [InputParameter("Gamma", sortIndex: 1, 0.01, 1, 0.01, 2)] + public double Gamma { get; set; } = 0.1; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Ltma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"Laguerre {Gamma:F2} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => 4; // Based on WarmupPeriod in Ltma + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public LtmaIndicator() : base() + public LtmaIndicator() { - Name = "LTMA - Laguerre Transform Moving Average"; - Description = "Moving average using Laguerre polynomials, offering adjustable smoothing and lag reduction."; + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); + Name = "LTMA - Laguerre Time Moving Average"; + Description = "Laguerre Time Moving Average"; + Series = new(name: $"LTMA {Gamma}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Ltma(gamma: Gamma); - base.InitIndicator(); + ma = new Ltma(Gamma); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"LTMA {Gamma}:{SourceName}"; } diff --git a/quantower/Averages/MaafIndicator.cs b/quantower/Averages/MaafIndicator.cs index 49a94d01..7cde3f58 100644 --- a/quantower/Averages/MaafIndicator.cs +++ b/quantower/Averages/MaafIndicator.cs @@ -1,27 +1,61 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class MaafIndicator : IndicatorBase +public class MaafIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 39; + [InputParameter("Periods", sortIndex: 1, 3, 1000, 1, 0)] + public int Periods { get; set; } = 39; - [InputParameter("Threshold", sortIndex: 5, minimum: 0, maximum: 1, increment: 0.001, decimalPlaces: 3)] - private double Threshold { get; set; } = 0.002; + [InputParameter("Threshold", sortIndex: 2, 0.0001, 0.1, 0.0001, 4)] + public double Threshold { get; set; } = 0.002; + + [InputParameter("Data source", sortIndex: 3, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Maaf? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"MAAF {Period} : {Threshold:F2} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public MaafIndicator() : base() + public MaafIndicator() { - Name = "MAAF - Median-Average Adaptive Filter"; - Description = "Adaptive filter combining median and average, reducing noise while preserving trend responsiveness."; + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); + Name = "MAAF - Median Adaptive Averaging Filter"; + Description = "Median Adaptive Averaging Filter (Note: This indicator may have consistency issues)"; + Series = new(name: $"MAAF {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - base.InitIndicator(); - ma = new Maaf(period: Period, threshold: Threshold); + ma = new Maaf(Periods, Threshold); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"MAAF {Periods}:{Threshold}:{SourceName}"; } diff --git a/quantower/Averages/MamaIndicator.cs b/quantower/Averages/MamaIndicator.cs index 3f243e0a..0c19be79 100644 --- a/quantower/Averages/MamaIndicator.cs +++ b/quantower/Averages/MamaIndicator.cs @@ -1,25 +1,65 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class MamaIndicator : IndicatorBase +public class MamaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Fast limit", sortIndex: 2, 0, 1, 0.01, 2)] - public double Fast { get; set; } = 0.4; - [InputParameter("Slow limit", sortIndex: 3, 0, 1, 0.01, 2)] - public double Slow { get; set; } = 0.04; + [InputParameter("Fast Limit", sortIndex: 1, 0.01, 1, 0.01, 2)] + public double FastLimit { get; set; } = 0.5; + + [InputParameter("Slow Limit", sortIndex: 2, 0.01, 1, 0.01, 2)] + public double SlowLimit { get; set; } = 0.05; + + [InputParameter("Data source", sortIndex: 3, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + private Mama? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"MAMA : {Fast} : {Slow} : {SourceName}"; + protected LineSeries? MamaSeries; + protected LineSeries? FamaSeries; + protected string? SourceName; + public int MinHistoryDepths => 6; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public MamaIndicator() : base() + public MamaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "MAMA - MESA Adaptive Moving Average"; - Description = "Adaptive moving average using MESA algorithm to adjust to market cycles and reduce lag."; + Description = "MESA Adaptive Moving Average"; + MamaSeries = new(name: "MAMA", color: Color.Yellow, width: 2, style: LineStyle.Solid); + FamaSeries = new(name: "FAMA", color: Color.Red, width: 2, style: LineStyle.Solid); + AddLineSeries(MamaSeries); + AddLineSeries(FamaSeries); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Mama(Fast, Slow); - base.InitIndicator(); + ma = new Mama(FastLimit, SlowLimit); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + MamaSeries!.SetValue(result.Value); + FamaSeries!.SetValue(ma.Fama.Value); + } + + public override string ShortName => $"MAMA {FastLimit}:{SlowLimit}:{SourceName}"; } diff --git a/quantower/Averages/MgdiIndicator.cs b/quantower/Averages/MgdiIndicator.cs index 525c449b..f8ea96df 100644 --- a/quantower/Averages/MgdiIndicator.cs +++ b/quantower/Averages/MgdiIndicator.cs @@ -1,27 +1,61 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class MgdiIndicator : IndicatorBase +public class MgdiIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; - [InputParameter("k Factor", sortIndex: 2, minimum: 0.0, maximum: 1.0, increment: 0.1, decimalPlaces: 2)] - public double kfactor { get; set; } = 0.6; + [InputParameter("K-Factor", sortIndex: 2, 0.1, 2, 0.1, 1)] + public double KFactor { get; set; } = 0.6; + + [InputParameter("Data source", sortIndex: 3, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Mgdi? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"MGDI {Period} : {kfactor:F2} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public MgdiIndicator() : base() + public MgdiIndicator() { - Name = "MGDI - McGinley Dynamic Index"; - Description = "Adaptive moving average that adjusts to market speed, reducing whipsaws in trending markets."; + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); + Name = "MGDI - McGinley Dynamic Indicator"; + Description = "McGinley Dynamic Indicator"; + Series = new(name: $"MGDI {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Mgdi(period: Period, kFactor: kfactor); - base.InitIndicator(); + ma = new Mgdi(Periods, KFactor); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"MGDI {Periods}:{KFactor}:{SourceName}"; } diff --git a/quantower/Averages/MmaIndicator.cs b/quantower/Averages/MmaIndicator.cs index b37cc874..71e59448 100644 --- a/quantower/Averages/MmaIndicator.cs +++ b/quantower/Averages/MmaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class MmaIndicator : IndicatorBase +public class MmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Mma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"MMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public MmaIndicator() : base() + public MmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "MMA - Modified Moving Average"; - Description = "Variation of EMA that reduces lag and smooths price action, balancing responsiveness and stability."; + Description = "Modified Moving Average"; + Series = new(name: $"MMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - base.InitIndicator(); - ma = new Mma(period: Period); + ma = new Mma(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"MMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/PwmaIndicator.cs b/quantower/Averages/PwmaIndicator.cs index fac30512..950dc051 100644 --- a/quantower/Averages/PwmaIndicator.cs +++ b/quantower/Averages/PwmaIndicator.cs @@ -1,24 +1,58 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class PwmaIndicator : IndicatorBase +public class PwmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Pwma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"PWMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public PwmaIndicator() : base() + public PwmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "PWMA - Pascal's Weighted Moving Average"; - Description = "Moving average using Pascal's triangle coefficients, emphasizing recent data with smooth transitions."; + Description = "Pascal's Weighted Moving Average"; + Series = new(name: $"PWMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - base.InitIndicator(); - ma = new Pwma(period: Period); + ma = new Pwma(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"PWMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/QemaIndicator.cs b/quantower/Averages/QemaIndicator.cs index c4403eea..5ce7d79d 100644 --- a/quantower/Averages/QemaIndicator.cs +++ b/quantower/Averages/QemaIndicator.cs @@ -1,30 +1,67 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class QemaIndicator : IndicatorBase +public class QemaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("alpha 1", sortIndex: 1, minimum: 0.01, maximum: 1.0, increment: 0.01, decimalPlaces: 2)] - public double k1 { get; set; } = 0.2; + [InputParameter("K1", sortIndex: 1, 0.01, 1, 0.01, 2)] + public double K1 { get; set; } = 0.2; + + [InputParameter("K2", sortIndex: 2, 0.01, 1, 0.01, 2)] + public double K2 { get; set; } = 0.2; + + [InputParameter("K3", sortIndex: 3, 0.01, 1, 0.01, 2)] + public double K3 { get; set; } = 0.2; + + [InputParameter("K4", sortIndex: 4, 0.01, 1, 0.01, 2)] + public double K4 { get; set; } = 0.2; + + [InputParameter("Data source", sortIndex: 5, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; - [InputParameter("alpha 2", sortIndex: 2, minimum: 0.01, maximum: 1.0, increment: 0.01, decimalPlaces: 2)] - public double k2 { get; set; } = 0.3; - [InputParameter("alpha 3", sortIndex: 3, minimum: 0.01, maximum: 1.0, increment: 0.01, decimalPlaces: 2)] - public double k3 { get; set; } = 0.4; - [InputParameter("alpha 4", sortIndex: 4, minimum: 0.01, maximum: 1.0, increment: 0.01, decimalPlaces: 2)] - public double k4 { get; set; } = 0.5; private Qema? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"QEMA {k1:F2} : {k2:F2} : {k3:F2} : {k4:F2} :{SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => (int)((2 - Math.Min(Math.Min(K1, K2), Math.Min(K3, K4))) / Math.Min(Math.Min(K1, K2), Math.Min(K3, K4))); + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public QemaIndicator() : base() + public QemaIndicator() { - Name = "QEMA - Quad Exponential Moving Average"; - Description = "Combines four EMAs with different smoothing factors to reduce lag and improve trend following."; + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); + Name = "QEMA - Quadruple Exponential Moving Average"; + Description = "Quadruple Exponential Moving Average"; + Series = new(name: $"QEMA {K1},{K2},{K3},{K4}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - base.InitIndicator(); - ma = new Qema(k1, k2, k3, k4); + ma = new Qema(K1, K2, K3, K4); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"QEMA {K1},{K2},{K3},{K4}:{SourceName}"; } diff --git a/quantower/Averages/RemaIndicator.cs b/quantower/Averages/RemaIndicator.cs index c8f50273..ea544d08 100644 --- a/quantower/Averages/RemaIndicator.cs +++ b/quantower/Averages/RemaIndicator.cs @@ -1,27 +1,61 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class RemaIndicator : IndicatorBase +public class RemaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; - [InputParameter("Regularization Factor", sortIndex: 2, minimum: 0, maximum: 2.5, increment: 0.1, decimalPlaces: 1)] + [InputParameter("Lambda", sortIndex: 2, 0, 1, 0.01, 2)] public double Lambda { get; set; } = 0.5; + [InputParameter("Data source", sortIndex: 3, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + private Rema? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"REMA {Period} : {Lambda:F2} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public RemaIndicator() : base() + public RemaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "REMA - Regularized Exponential Moving Average"; - Description = "EMA variant with regularization to reduce noise and improve stability in volatile markets."; + Description = "Regularized Exponential Moving Average"; + Series = new(name: $"REMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - base.InitIndicator(); - ma = new Rema(period: Period, lambda: Lambda); + ma = new Rema(Periods, Lambda); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"REMA {Periods}:{Lambda}:{SourceName}"; } diff --git a/quantower/Averages/RmaIndicator.cs b/quantower/Averages/RmaIndicator.cs index 41b9e333..aadeabfa 100644 --- a/quantower/Averages/RmaIndicator.cs +++ b/quantower/Averages/RmaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class RmaIndicator : IndicatorBase +public class RmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Rma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"RMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods * 2; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public RmaIndicator() : base() + public RmaIndicator() { - Name = "RMA - Wilder's Moving Average"; - Description = "Smoothed moving average that reduces whipsaws, commonly used in RSI calculations."; + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); + Name = "RMA - Relative Moving Average (Wilder's Moving Average)"; + Description = "Relative Moving Average, also known as Wilder's Moving Average"; + Series = new(name: $"RMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Rma(Period); - base.InitIndicator(); + ma = new Rma(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"RMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/SinemaIndicator.cs b/quantower/Averages/SinemaIndicator.cs index 3ebeb128..306e66ae 100644 --- a/quantower/Averages/SinemaIndicator.cs +++ b/quantower/Averages/SinemaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class SinemaIndicator : IndicatorBase +public class SinemaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Sinema? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"SINEMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public SinemaIndicator() : base() + public SinemaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "SINEMA - Sine-Weighted Moving Average"; - Description = "Moving average using sine function for weighting, balancing recent and historical price data."; + Description = "Sine-Weighted Moving Average"; + Series = new(name: $"SINEMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Sinema(Period); - base.InitIndicator(); + ma = new Sinema(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"SINEMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/SmaIndicator.cs b/quantower/Averages/SmaIndicator.cs index a90e30a5..e71b97ae 100644 --- a/quantower/Averages/SmaIndicator.cs +++ b/quantower/Averages/SmaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class SmaIndicator : IndicatorBase +public class SmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Sma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"SMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public SmaIndicator() : base() + public SmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "SMA - Simple Moving Average"; - Description = "Basic moving average that calculates the arithmetic mean of prices over a specified period."; + Description = "Simple Moving Average"; + Series = new(name: $"SMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Sma(Period); - base.InitIndicator(); + ma = new Sma(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"SMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/SmmaIndicator.cs b/quantower/Averages/SmmaIndicator.cs index 49186bfe..675e5c3f 100644 --- a/quantower/Averages/SmmaIndicator.cs +++ b/quantower/Averages/SmmaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class SmmaIndicator : IndicatorBase +public class SmmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Smma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"SMMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public SmmaIndicator() : base() + public SmmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "SMMA - Smoothed Moving Average"; - Description = "Moving average that gives more weight to recent data while retaining all historical data."; + Description = "Smoothed Moving Average"; + Series = new(name: $"SMMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Smma(Period); - base.InitIndicator(); + ma = new Smma(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"SMMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/T3Indicator.cs b/quantower/Averages/T3Indicator.cs index 81dac3f4..d46f338c 100644 --- a/quantower/Averages/T3Indicator.cs +++ b/quantower/Averages/T3Indicator.cs @@ -1,30 +1,64 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class T3Indicator : IndicatorBase +public class T3Indicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; - [InputParameter("Vfactor", sortIndex: 2, 0, 1, 0.01, 2)] - public double Vfactor { get; set; } = 0.62; + [InputParameter("Volume Factor", sortIndex: 2, 0, 1, 0.01, 2)] + public double VolumeFactor { get; set; } = 0.7; - [InputParameter("Use SMA for warmup", sortIndex: 3)] - public bool UseSma { get; set; } = false; + [InputParameter("Use SMA", sortIndex: 3)] + public bool UseSma { get; set; } = true; + + [InputParameter("Data source", sortIndex: 4, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private T3? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"T3 {Period} : {Vfactor:F2} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public T3Indicator() : base() + public T3Indicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "T3 - Tillson T3 Moving Average"; - Description = "Triple exponential moving average with reduced lag and smoothing, adjustable via volume factor."; + Description = "Tillson T3 Moving Average"; + Series = new(name: $"T3 {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new T3(period: Period, vfactor: Vfactor, useSma: UseSma); - base.InitIndicator(); + ma = new T3(Periods, VolumeFactor, UseSma); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"T3 {Periods}:{VolumeFactor}:{UseSma}:{SourceName}"; } diff --git a/quantower/Averages/TemaIndicator.cs b/quantower/Averages/TemaIndicator.cs index 236e893c..208cb0d1 100644 --- a/quantower/Averages/TemaIndicator.cs +++ b/quantower/Averages/TemaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class TemaIndicator : IndicatorBase +public class TemaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Tema? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"TEMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => (int)Math.Ceiling(-Periods * Math.Log(1 - 0.85)); + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public TemaIndicator() : base() + public TemaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "TEMA - Triple Exponential Moving Average"; - Description = "Moving average that applies EMA three times to reduce lag and improve responsiveness to trends."; + Description = "Triple Exponential Moving Average"; + Series = new(name: $"TEMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - base.InitIndicator(); - ma = new Tema(period: Period); + ma = new Tema(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"TEMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/TrimaIndicator.cs b/quantower/Averages/TrimaIndicator.cs index 2ac8d091..443331ec 100644 --- a/quantower/Averages/TrimaIndicator.cs +++ b/quantower/Averages/TrimaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class TrimaIndicator : IndicatorBase +public class TrimaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Trima? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"TRIMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public TrimaIndicator() : base() + public TrimaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "TRIMA - Triangular Moving Average"; - Description = "Weighted moving average giving more importance to the middle of the period for smoother output."; + Description = "Triangular Moving Average"; + Series = new(name: $"TRIMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Trima(Period); - base.InitIndicator(); + ma = new Trima(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"TRIMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/VidyaIndicator.cs b/quantower/Averages/VidyaIndicator.cs index b45c117c..a2b37948 100644 --- a/quantower/Averages/VidyaIndicator.cs +++ b/quantower/Averages/VidyaIndicator.cs @@ -1,28 +1,64 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class VidyaIndicator : IndicatorBase +public class VidyaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Short Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; - [InputParameter("Long Period", sortIndex: 2, 1, 2000, 1, 0)] - public int LPeriod { get; set; } = 40; - [InputParameter("Alpha", sortIndex: 3, 0, 1, 0.1, 1)] - public double Alpha { get; set; } = 0.4; + [InputParameter("Short Period", sortIndex: 1, 1, 1000, 1, 0)] + public int ShortPeriod { get; set; } = 14; + + [InputParameter("Long Period", sortIndex: 2, 0, 1000, 1, 0)] + public int LongPeriod { get; set; } = 0; + + [InputParameter("Alpha", sortIndex: 3, 0.01, 1, 0.01, 2)] + public double Alpha { get; set; } = 0.2; + + [InputParameter("Data source", sortIndex: 4, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Vidya? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"VIDYA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => LongPeriod == 0 ? ShortPeriod * 4 : LongPeriod; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public VidyaIndicator() : base() + public VidyaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "VIDYA - Variable Index Dynamic Average"; - Description = "Adaptive moving average that adjusts based on market volatility for improved trend following."; + Description = "Variable Index Dynamic Average"; + Series = new(name: $"VIDYA {ShortPeriod}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Vidya(Period, LPeriod, Alpha); - base.InitIndicator(); + ma = new Vidya(ShortPeriod, LongPeriod, Alpha); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"VIDYA {ShortPeriod}:{LongPeriod}:{Alpha}:{SourceName}"; } diff --git a/quantower/Averages/WmaIndicator.cs b/quantower/Averages/WmaIndicator.cs index aec32407..1c00b0ec 100644 --- a/quantower/Averages/WmaIndicator.cs +++ b/quantower/Averages/WmaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class WmaIndicator : IndicatorBase +public class WmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Wma? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"WMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public WmaIndicator() : base() + public WmaIndicator() { + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); Name = "WMA - Weighted Moving Average"; - Description = "Moving average that assigns higher weights to recent data points for improved responsiveness."; + Description = "Weighted Moving Average"; + Series = new(name: $"WMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Wma(Period); - base.InitIndicator(); + ma = new Wma(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"WMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/ZlemaIndicator.cs b/quantower/Averages/ZlemaIndicator.cs index f89c8188..5ef974ef 100644 --- a/quantower/Averages/ZlemaIndicator.cs +++ b/quantower/Averages/ZlemaIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class ZlemaIndicator : IndicatorBase +public class ZlemaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Zlema? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"ZLEMA {Period} : {SourceName}"; + protected LineSeries? Series; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public ZlemaIndicator() : base() + public ZlemaIndicator() { - Name = "ZLEMA - Zero-Lag Exponential Moving Average"; - Description = "EMA variant that reduces lag by using linear extrapolation, providing faster response to price changes."; + OnBackGround = true; + SeparateWindow = false; + SourceName = Source.ToString(); + Name = "ZLEMA - Zero Lag Exponential Moving Average"; + Description = "Zero Lag Exponential Moving Average"; + Series = new(name: $"ZLEMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); } - protected override void InitIndicator() + protected override void OnInit() { - base.InitIndicator(); - ma = new Zlema(Period); + ma = new Zlema(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetValue(result.Value); + } + + public override string ShortName => $"ZLEMA {Periods}:{SourceName}"; } diff --git a/quantower/Averages/Averages.csproj b/quantower/Averages/_Averages.csproj similarity index 89% rename from quantower/Averages/Averages.csproj rename to quantower/Averages/_Averages.csproj index 692601e3..6b270b32 100644 --- a/quantower/Averages/Averages.csproj +++ b/quantower/Averages/_Averages.csproj @@ -1,5 +1,6 @@  + Averages Indicator bin\$(Configuration)\ true @@ -14,7 +15,8 @@ - + + ..\..\.github\TradingPlatform.BusinessLayer.dll diff --git a/quantower/IndicatorExtensions.cs b/quantower/IndicatorExtensions.cs new file mode 100644 index 00000000..9de6a9d3 --- /dev/null +++ b/quantower/IndicatorExtensions.cs @@ -0,0 +1,148 @@ +using TradingPlatform.BusinessLayer; +using System.Drawing; +using System.Drawing.Drawing2D; + +namespace QuanTAlib; + +public enum SourceType +{ + Open, High, Low, Close, HL2, OC2, OHL3, HLC3, OHLC4, HLCC4 +} +public static class IndicatorExtensions +{ + public static TValue GetInputValue(this Indicator indicator, UpdateArgs args, SourceType source) + { + var historicalData = indicator.HistoricalData; + + TBar bar = new TBar( + Time: historicalData.Time(), + Open: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Open], + High: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.High], + Low: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Low], + Close: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Close], + Volume: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Volume], + IsNew: args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar + ); + + double price = source switch + { + SourceType.Open => bar.Open, + SourceType.High => bar.High, + SourceType.Low => bar.Low, + SourceType.Close => bar.Close, + SourceType.HL2 => bar.HL2, + SourceType.OC2 => bar.OC2, + SourceType.OHL3 => bar.OHL3, + SourceType.HLC3 => bar.HLC3, + SourceType.OHLC4 => bar.OHLC4, + SourceType.HLCC4 => bar.HLCC4, + _ => bar.Close + }; + + return new TValue(bar.Time, price, bar.IsNew); + } + + public static TBar GetInputBar(this Indicator indicator, UpdateArgs args) + { + var historicalData = indicator.HistoricalData; + + return new TBar( + Time: historicalData.Time(), + Open: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Open], + High: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.High], + Low: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Low], + Close: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Close], + Volume: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Volume], + IsNew: args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar + ); + } + +#pragma warning disable CA1416 // Validate platform compatibility + + public static void PaintSmoothCurve(this Indicator indicator, PaintChartEventArgs args, LineSeries series, int warmupPeriod, bool showColdValues = true, double tension = 0.2) + { + if (!series.Visible || indicator.CurrentChart == null) + return; + + Graphics gr = args.Graphics; + var mainWindow = indicator.CurrentChart.MainWindow; + var converter = mainWindow.CoordinatesConverter; + var clientRect = mainWindow.ClientRectangle; + + gr.SetClip(clientRect); + DateTime leftTime = new[] { converter.GetTime(clientRect.Left), indicator.HistoricalData.Time(indicator!.Count - 1) }.Max(); + DateTime rightTime = new[] { converter.GetTime(clientRect.Right), indicator.HistoricalData.Time(0) }.Min(); + + int leftIndex = (int)indicator.HistoricalData.GetIndexByTime(leftTime.Ticks) + 1; + int rightIndex = (int)indicator.HistoricalData.GetIndexByTime(rightTime.Ticks); + + List allPoints = new List(); + for (int i = rightIndex; i < leftIndex; i++) + { + int barX = (int)converter.GetChartX(indicator.HistoricalData.Time(i)); + int barY = (int)converter.GetChartY(series[i]); + int halfBarWidth = indicator.CurrentChart.BarsWidth / 2; + Point point = new Point(barX + halfBarWidth, barY); + allPoints.Add(point); + } + + if (allPoints.Count > 1) + { + + if (allPoints.Count < 2) return; + + using (Pen defaultPen = new(series.Color, series.Width) { DashStyle = ConvertLineStyleToDashStyle(series.Style) }) + using (Pen coldPen = new(series.Color, series.Width) { DashStyle = DashStyle.Dot }) + { + int hotCount = indicator.Count - warmupPeriod - rightIndex; + // Draw the hot part + if (hotCount > 0) + { + var hotPoints = allPoints.Take(Math.Min(hotCount + 1, allPoints.Count)).ToArray(); + gr.DrawCurve(defaultPen, hotPoints, 0, hotPoints.Length - 1, (float)tension); + } + + // Draw the cold part + if (showColdValues && hotCount < allPoints.Count) + { + var coldPoints = allPoints.Skip(Math.Max(0, hotCount)).ToArray(); + gr.DrawCurve(coldPen, coldPoints, 0, coldPoints.Length - 1, (float)tension); + } + } + } + } + public static void DrawText(this Indicator indicator, PaintChartEventArgs args, string text) + { + if (indicator.CurrentChart == null) + return; + + Graphics gr = args.Graphics; + var clientRect = indicator.CurrentChart.MainWindow.ClientRectangle; + + Font font = new Font("Inter", 8); + SizeF textSize = gr.MeasureString(text, font); + RectangleF textRect = new RectangleF(clientRect.Left + 5, + clientRect.Bottom - textSize.Height - 10, + textSize.Width + 10, textSize.Height + 10); + + gr.FillRectangle(Brushes.DarkBlue, textRect); + gr.DrawString(text, font, Brushes.White, new PointF(textRect.X + 6, textRect.Y + 5)); + } + + private static DashStyle ConvertLineStyleToDashStyle(LineStyle lineStyle) + { + return lineStyle switch + { + LineStyle.Solid => DashStyle.Solid, + LineStyle.Dash => DashStyle.Dash, + LineStyle.Dot => DashStyle.Dot, + LineStyle.DashDot => DashStyle.DashDot, + _ => DashStyle.Solid, + }; + } + +} + + + + diff --git a/quantower/Statistics/CurvatureIndicator.cs b/quantower/Statistics/CurvatureIndicator.cs index 2ef393e0..4ba48c9e 100644 --- a/quantower/Statistics/CurvatureIndicator.cs +++ b/quantower/Statistics/CurvatureIndicator.cs @@ -1,25 +1,63 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class CurvatureIndicator : IndicatorBase +public class CurvatureIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)] - public int Period { get; set; } = 20; + [InputParameter("Periods", sortIndex: 1, 3, 1000, 1, 0)] + public int Periods { get; set; } = 20; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Curvature? curvature; - protected override AbstractBase QuanTAlib => curvature!; - public override string ShortName => $"CURVATURE {Period} : {SourceName}"; + protected LineSeries? CurvatureSeries; + protected LineSeries? LineSeries; + protected string? SourceName; + public int MinHistoryDepths => Periods * 2 - 1; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public CurvatureIndicator() { - Name = "CURVATURE - Rate of Change of Slope"; - Description = "Measures the rate of change of the slope, indicating acceleration or deceleration in price movement."; + Name = "Curvature"; + Description = "Calculates the rate of change of the slope over a specified period"; SeparateWindow = true; + SourceName = Source.ToString(); + + CurvatureSeries = new("Curvature", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(CurvatureSeries); } - protected override void InitIndicator() + protected override void OnInit() { - curvature = new(Period); - MinHistoryDepths = curvature.WarmupPeriod; + curvature = new Curvature(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = curvature!.Calc(input); + + CurvatureSeries!.SetValue(result.Value); + if (curvature.Line.HasValue) + { + LineSeries!.SetValue(curvature.Line.Value); + } + } + + public override string ShortName => $"Curvature ({Periods}:{SourceName})"; } diff --git a/quantower/Statistics/EntropyIndicator.cs b/quantower/Statistics/EntropyIndicator.cs index 5614c288..6dfd343b 100644 --- a/quantower/Statistics/EntropyIndicator.cs +++ b/quantower/Statistics/EntropyIndicator.cs @@ -1,26 +1,58 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class EntropyIndicator : IndicatorBase +public class EntropyIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)] - public int Period { get; set; } = 50; + [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)] + public int Periods { get; set; } = 20; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Entropy? entropy; - protected override AbstractBase QuanTAlib => entropy!; - public override string ShortName => $"ENTROPY {Period} : {SourceName}"; + protected LineSeries? EntropySeries; + protected string? SourceName; + public int MinHistoryDepths => 2; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public EntropyIndicator() : base() + public EntropyIndicator() { - Name = "ENTROPY - Entropy"; - Description = "Measures the randomness or uncertainty in price movements, useful for identifying market phases."; + Name = "Entropy"; + Description = "Measures the unpredictability of data using Shannon's Entropy"; SeparateWindow = true; + SourceName = Source.ToString(); + + EntropySeries = new("Entropy", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(EntropySeries); } - protected override void InitIndicator() + protected override void OnInit() { - entropy = new(Period); - MinHistoryDepths = entropy.WarmupPeriod; - base.InitIndicator(); + entropy = new Entropy(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = entropy!.Calc(input); + + EntropySeries!.SetValue(result.Value); + } + + public override string ShortName => $"Entropy ({Periods}:{SourceName})"; } diff --git a/quantower/Statistics/KurtosisIndicator.cs b/quantower/Statistics/KurtosisIndicator.cs index 086bb61d..620f53dd 100644 --- a/quantower/Statistics/KurtosisIndicator.cs +++ b/quantower/Statistics/KurtosisIndicator.cs @@ -1,26 +1,58 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class KurtosisIndicator : IndicatorBase +public class KurtosisIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 4, 2000, 1, 0)] - public int Period { get; set; } = 20; + [InputParameter("Periods", sortIndex: 1, 4, 1000, 1, 0)] + public int Periods { get; set; } = 20; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Kurtosis? kurtosis; - protected override AbstractBase QuanTAlib => kurtosis!; - public override string ShortName => $"KURTOSIS {Period} : {SourceName}"; + protected LineSeries? KurtosisSeries; + protected string? SourceName; + public int MinHistoryDepths => Periods - 1; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public KurtosisIndicator() : base() + public KurtosisIndicator() { - Name = "KURTOSIS - Relative Flatness"; - Description = "Measures the 'tailedness' of price distribution, indicating potential for extreme market movements."; + Name = "Kurtosis"; + Description = "Measures the 'tailedness' of the probability distribution of a real-valued random variable"; SeparateWindow = true; + SourceName = Source.ToString(); + + KurtosisSeries = new("Kurtosis", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(KurtosisSeries); } - protected override void InitIndicator() + protected override void OnInit() { - kurtosis = new(Period); - MinHistoryDepths = kurtosis.WarmupPeriod; - base.InitIndicator(); + kurtosis = new Kurtosis(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = kurtosis!.Calc(input); + + KurtosisSeries!.SetValue(result.Value); + } + + public override string ShortName => $"Kurtosis ({Periods}:{SourceName})"; } diff --git a/quantower/Statistics/MaxIndicator.cs b/quantower/Statistics/MaxIndicator.cs index b8af5012..23a67501 100644 --- a/quantower/Statistics/MaxIndicator.cs +++ b/quantower/Statistics/MaxIndicator.cs @@ -1,29 +1,61 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class MaxIndicator : IndicatorBase +public class MaxIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 50; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 20; - [InputParameter("Decay to mean", sortIndex: 1, minimum: 0.00, maximum: 100.0, increment: 0.01, decimalPlaces: 2)] - public double Decay { get; set; } = 0.1; + [InputParameter("Decay", sortIndex: 2, 0, 10, 0.01, 2)] + public double Decay { get; set; } = 0; + + [InputParameter("Data source", sortIndex: 3, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.High; private Max? ma; - protected override AbstractBase QuanTAlib => ma!; - public override string ShortName => $"MAX {Period} : {Decay:F2} : {SourceName}"; + protected LineSeries? MaxSeries; + protected string? SourceName; + public int MinHistoryDepths => 0; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public MaxIndicator() : base() + public MaxIndicator() { - Name = "MAX - Maximum value (with decay)"; - Description = "Tracks the maximum value over a period, with a decay factor to gradually adjust to new highs."; + Name = "Max"; + Description = "Calculates the maximum value over a specified period, with an optional decay factor"; + SeparateWindow = false; + SourceName = Source.ToString(); + + MaxSeries = new("Max", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(MaxSeries); } - protected override void InitIndicator() + protected override void OnInit() { - ma = new Max(Period, Decay); - MinHistoryDepths = ma.WarmupPeriod; - Source = 2; - base.InitIndicator(); + ma = new Max(Periods, Decay); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + MaxSeries!.SetValue(result.Value); + } + + public override string ShortName => $"Max ({Periods}, {Decay:F2}:{SourceName})"; } diff --git a/quantower/Statistics/MedianIndicator.cs b/quantower/Statistics/MedianIndicator.cs index 05d500c4..471ace45 100644 --- a/quantower/Statistics/MedianIndicator.cs +++ b/quantower/Statistics/MedianIndicator.cs @@ -1,24 +1,58 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class MedianIndicator : IndicatorBase +public class MedianIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 50; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 20; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Median? med; - protected override AbstractBase QuanTAlib => med!; - public override string ShortName => $"MEDIAN {Period} : {SourceName}"; - public MedianIndicator() : base() + protected LineSeries? MedianSeries; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public MedianIndicator() { - Name = "MEDIAN - Median historical value"; - Description = "Calculates the middle value of price data over a specified period, less affected by outliers than mean."; + Name = "Median"; + Description = "Calculates the median value over a specified period"; + SeparateWindow = false; + SourceName = Source.ToString(); + + MedianSeries = new("Median", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(MedianSeries); } - protected override void InitIndicator() + protected override void OnInit() { - med = new Median(Period); - MinHistoryDepths = med.WarmupPeriod; - base.InitIndicator(); + med = new Median(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = med!.Calc(input); + + MedianSeries!.SetValue(result.Value); + } + + public override string ShortName => $"Median ({Periods}:{SourceName})"; } diff --git a/quantower/Statistics/MinIndicator.cs b/quantower/Statistics/MinIndicator.cs index 3399bdc7..a7fa2e59 100644 --- a/quantower/Statistics/MinIndicator.cs +++ b/quantower/Statistics/MinIndicator.cs @@ -1,28 +1,61 @@ -using TradingPlatform.BusinessLayer; +using System.Drawing; +using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class MinIndicator : IndicatorBase +public class MinIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 50; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 20; - [InputParameter("Decay to mean", sortIndex: 1, minimum: 0.00, maximum: 100.0, increment: 0.01, decimalPlaces: 2)] - public double Decay { get; set; } = 0.1; + [InputParameter("Decay", sortIndex: 2, 0, 10, 0.01, 2)] + public double Decay { get; set; } = 0; + + [InputParameter("Data source", sortIndex: 3, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Low; private Min? mi; - protected override AbstractBase QuanTAlib => mi!; - public override string ShortName => $"MIN {Period} : {Decay:F2} : {SourceName}"; - public MinIndicator() : base() + protected LineSeries? MinSeries; + protected string? SourceName; + public int MinHistoryDepths => 0; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public MinIndicator() { - Name = "MIN - Minimum value (with decay)"; - Description = "Tracks the minimum value over a period, with a decay factor to gradually adjust to new lows."; + Name = "Min"; + Description = "Calculates the minimum value over a specified period, with an optional decay factor"; + SeparateWindow = false; + SourceName = Source.ToString(); + + MinSeries = new("Min", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(MinSeries); } - protected override void InitIndicator() + protected override void OnInit() { - mi = new Min(Period, Decay); - MinHistoryDepths = mi.WarmupPeriod; - Source = 3; - base.InitIndicator(); + mi = new Min(Periods, Decay); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = mi!.Calc(input); + + MinSeries!.SetValue(result.Value); + } + + public override string ShortName => $"Min ({Periods}, {Decay:F2}:{SourceName})"; } diff --git a/quantower/Statistics/ModeIndicator.cs b/quantower/Statistics/ModeIndicator.cs index e14b17ad..7294ed2c 100644 --- a/quantower/Statistics/ModeIndicator.cs +++ b/quantower/Statistics/ModeIndicator.cs @@ -1,24 +1,58 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class ModeIndicator : IndicatorBase +public class ModeIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 50; + [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 20; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Mode? mode; - protected override AbstractBase QuanTAlib => mode!; - public override string ShortName => $"MODE {Period} : {SourceName}"; - public ModeIndicator() : base() + protected LineSeries? ModeSeries; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public ModeIndicator() { - Name = "MODE - Most frequent historical value"; - Description = "Identifies the most frequently occurring price value over a specified period, indicating price clusters."; + Name = "Mode"; + Description = "Calculates the most frequent value in a specified period"; + SeparateWindow = false; + SourceName = Source.ToString(); + + ModeSeries = new("Mode", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(ModeSeries); } - protected override void InitIndicator() + protected override void OnInit() { - mode = new Mode(Period); - MinHistoryDepths = mode.WarmupPeriod; - base.InitIndicator(); + mode = new Mode(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = mode!.Calc(input); + + ModeSeries!.SetValue(result.Value); + } + + public override string ShortName => $"Mode ({Periods}:{SourceName})"; } diff --git a/quantower/Statistics/PercentileIndicator.cs b/quantower/Statistics/PercentileIndicator.cs index 0e4a5e91..ba861496 100644 --- a/quantower/Statistics/PercentileIndicator.cs +++ b/quantower/Statistics/PercentileIndicator.cs @@ -1,28 +1,61 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; -namespace QuanTAlib; -public class PercentileIndicator : IndicatorBase -{ - [InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)] - public int Period { get; set; } = 20; - [InputParameter("Percent", sortIndex: 2, 0, 100, 1, 0)] - public double Percent { get; set; } = 50; +namespace QuanTAlib; + +public class PercentileIndicator : Indicator, IWatchlistIndicator +{ + [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)] + public int Periods { get; set; } = 20; + + [InputParameter("Percentile", sortIndex: 2, 0, 100, 0.1, 1)] + public double PercentileValue { get; set; } = 50; + + [InputParameter("Data source", sortIndex: 3, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Percentile? percentile; - protected override AbstractBase QuanTAlib => percentile!; - public override string ShortName => $"PERCENTILE {Period} {Percent:F0}% : {SourceName}"; + protected LineSeries? PercentileSeries; + protected string? SourceName; + public int MinHistoryDepths => 2; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public PercentileIndicator() : base() + public PercentileIndicator() { - Name = "PERCENTILE - n-th Percentile"; - Description = "Calculates the value below which a given percentage of observations falls within a specified period."; + Name = "Percentile"; + Description = "Calculates the value at a specified percentile in a given period of data points"; SeparateWindow = false; + SourceName = Source.ToString(); + + PercentileSeries = new("Percentile", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(PercentileSeries); } - protected override void InitIndicator() + protected override void OnInit() { - percentile = new(Period, Percent); - MinHistoryDepths = percentile.WarmupPeriod; - base.InitIndicator(); + percentile = new Percentile(Periods, PercentileValue); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = percentile!.Calc(input); + + PercentileSeries!.SetValue(result.Value); + } + + public override string ShortName => $"Percentile ({Periods}, {PercentileValue}%:{SourceName})"; } diff --git a/quantower/Statistics/SkewIndicator.cs b/quantower/Statistics/SkewIndicator.cs index 7cf67cb9..6f684970 100644 --- a/quantower/Statistics/SkewIndicator.cs +++ b/quantower/Statistics/SkewIndicator.cs @@ -1,26 +1,58 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class SkewIndicator : IndicatorBase +public class SkewIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 3, 2000, 1, 0)] - public int Period { get; set; } = 20; + [InputParameter("Periods", sortIndex: 1, 3, 1000, 1, 0)] + public int Periods { get; set; } = 20; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Skew? skew; - protected override AbstractBase QuanTAlib => skew!; - public override string ShortName => $"SKEW {Period} : {SourceName}"; + protected LineSeries? SkewSeries; + protected string? SourceName; + public int MinHistoryDepths => 3; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public SkewIndicator() : base() + public SkewIndicator() { - Name = "SKEW - Skewness"; - Description = "Measures the asymmetry of price distribution, indicating potential trend direction or reversal."; + Name = "Skew"; + Description = "Measures the asymmetry of the probability distribution of a real-valued random variable about its mean"; SeparateWindow = true; + SourceName = Source.ToString(); + + SkewSeries = new("Skew", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(SkewSeries); } - protected override void InitIndicator() + protected override void OnInit() { - skew = new(Period); - MinHistoryDepths = skew.WarmupPeriod; - base.InitIndicator(); + skew = new Skew(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = skew!.Calc(input); + + SkewSeries!.SetValue(result.Value); + } + + public override string ShortName => $"Skew ({Periods}:{SourceName})"; } diff --git a/quantower/Statistics/SlopeIndicator.cs b/quantower/Statistics/SlopeIndicator.cs index 7d6b65db..c5d32741 100644 --- a/quantower/Statistics/SlopeIndicator.cs +++ b/quantower/Statistics/SlopeIndicator.cs @@ -1,25 +1,82 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class SlopeIndicator : IndicatorBase +public class SlopeIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)] - public int Period { get; set; } = 20; + [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)] + public int Periods { get; set; } = 20; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Slope? slope; - protected override AbstractBase QuanTAlib => slope!; - public override string ShortName => $"SLOPE {Period} : {SourceName}"; + protected LineSeries? SlopeSeries; + protected LineSeries? LineSeries; + protected string? SourceName; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public SlopeIndicator() { - Name = "SLOPE - Trend Slope"; - Description = "Measures the rate of change in price over a specified period, indicating trend strength and direction."; + Name = "Slope"; + Description = "Calculates the slope of a linear regression line for the specified period"; SeparateWindow = true; + SourceName = Source.ToString(); + + SlopeSeries = new("Slope", Color.Blue, 2, LineStyle.Solid); + LineSeries = new("Regression Line", Color.Red, 1, LineStyle.Solid); + AddLineSeries(SlopeSeries); + AddLineSeries(LineSeries); } - protected override void InitIndicator() + protected override void OnInit() { - slope = new(Period); - MinHistoryDepths = slope.WarmupPeriod; + slope = new Slope(Periods); + SourceName = Source.ToString(); + base.OnInit(); + } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = slope!.Calc(input); + + SlopeSeries!.SetValue(result.Value); + if (slope.Line.HasValue) + { + LineSeries!.SetValue(slope.Line.Value); + } + } + + public override string ShortName + { + get + { + var result = $"Slope ({Periods}:{SourceName})"; + if (slope != null) + { + result += $" Slope: {Math.Round(SlopeSeries!.GetValue(), 6)}"; + if (slope.Line.HasValue) + result += $", Line: {Math.Round(slope.Line.Value, 6)}"; + if (slope.Intercept.HasValue) + result += $", Intercept: {Math.Round(slope.Intercept.Value, 6)}"; + if (slope.RSquared.HasValue) + result += $", R²: {Math.Round(slope.RSquared.Value, 6)}"; + } + return result; + } } } diff --git a/quantower/Statistics/StddevIndicator.cs b/quantower/Statistics/StddevIndicator.cs index 6be198f9..0c1b557c 100644 --- a/quantower/Statistics/StddevIndicator.cs +++ b/quantower/Statistics/StddevIndicator.cs @@ -1,28 +1,61 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class StddevIndicator : IndicatorBase +public class StddevIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 20; + [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)] + public int Periods { get; set; } = 20; [InputParameter("Population", sortIndex: 2)] public bool IsPopulation { get; set; } = false; + [InputParameter("Data source", sortIndex: 3, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + private Stddev? stddev; - protected override AbstractBase QuanTAlib => stddev!; - public override string ShortName => $"STDDEV {Period} : {SourceName}"; - public StddevIndicator() : base() + protected LineSeries? StddevSeries; + protected string? SourceName; + public int MinHistoryDepths => 2; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public StddevIndicator() { - Name = "STDDEV - Standard Deviation"; - Description = "Measures price volatility by calculating the dispersion of prices from their average over a period."; + Name = "Standard Deviation"; + Description = "Measures the amount of variation or dispersion of a set of values"; SeparateWindow = true; + SourceName = Source.ToString(); + + StddevSeries = new("StdDev", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(StddevSeries); } - protected override void InitIndicator() + protected override void OnInit() { - stddev = new(Period, IsPopulation); - MinHistoryDepths = stddev.WarmupPeriod; - base.InitIndicator(); + stddev = new Stddev(Periods, IsPopulation); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = stddev!.Calc(input); + + StddevSeries!.SetValue(result.Value); + } + + public override string ShortName => $"StdDev ({Periods}, {(IsPopulation ? "Pop" : "Sample")}:{SourceName})"; } diff --git a/quantower/Statistics/VarianceIndicator.cs b/quantower/Statistics/VarianceIndicator.cs index d55552ad..9f0b5234 100644 --- a/quantower/Statistics/VarianceIndicator.cs +++ b/quantower/Statistics/VarianceIndicator.cs @@ -1,29 +1,61 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class VarianceIndicator : IndicatorBase +public class VarianceIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, minimum: 2, maximum: 2000, increment: 1, decimalPlaces: 0)] - public int Period { get; set; } = 20; + [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)] + public int Periods { get; set; } = 20; [InputParameter("Population", sortIndex: 2)] public bool IsPopulation { get; set; } = false; + [InputParameter("Data source", sortIndex: 3, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + private Variance? variance; - protected override AbstractBase QuanTAlib => variance!; - public override string ShortName => $"VAR {Period} : {SourceName}"; - public VarianceIndicator() : base() + protected LineSeries? VarianceSeries; + protected string? SourceName; + public int MinHistoryDepths => 2; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public VarianceIndicator() { - Name = "VAR - Variance"; - Description = "Measures the spread of price data around its mean, indicating volatility and potential trend changes."; + Name = "Variance"; + Description = "Measures the spread of a set of numbers from their average value"; SeparateWindow = true; + SourceName = Source.ToString(); + + VarianceSeries = new("Variance", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(VarianceSeries); } - protected override void InitIndicator() + protected override void OnInit() { - SeparateWindow = true; - variance = new(Period, IsPopulation); - MinHistoryDepths = variance.WarmupPeriod; - base.InitIndicator(); + variance = new Variance(Periods, IsPopulation); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = variance!.Calc(input); + + VarianceSeries!.SetValue(result.Value); + } + + public override string ShortName => $"Variance ({Periods}, {(IsPopulation ? "Pop" : "Sample")}:{SourceName})"; } diff --git a/quantower/Statistics/ZscoreIndicator.cs b/quantower/Statistics/ZscoreIndicator.cs index f9840d62..e708d54b 100644 --- a/quantower/Statistics/ZscoreIndicator.cs +++ b/quantower/Statistics/ZscoreIndicator.cs @@ -1,26 +1,58 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class ZScoreIndicator : IndicatorBase +public class ZscoreIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)] - public int Period { get; set; } = 20; + [InputParameter("Periods", sortIndex: 1, 2, 2000, 1, 0)] + public int Periods { get; set; } = 20; + + [InputParameter("Data source", sortIndex: 2, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; private Zscore? zScore; - protected override AbstractBase QuanTAlib => zScore!; - public override string ShortName => $"ZSCORE {Period} : {SourceName}"; + protected LineSeries? ZscoreSeries; + protected string? SourceName; + public int MinHistoryDepths => 2; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public ZScoreIndicator() : base() + public ZscoreIndicator() { - Name = "ZSCORE - Standard Score"; + Name = "Z-Score"; Description = "Measures how many standard deviations a price is from the mean, indicating overbought/oversold levels."; SeparateWindow = true; + SourceName = Source.ToString(); + + ZscoreSeries = new("Z-Score", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(ZscoreSeries); } - protected override void InitIndicator() + protected override void OnInit() { - zScore = new(Period); - MinHistoryDepths = zScore.WarmupPeriod; - base.InitIndicator(); + zScore = new Zscore(Periods); + SourceName = Source.ToString(); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = zScore!.Calc(input); + + ZscoreSeries!.SetValue(result.Value); + } + + public override string ShortName => $"Z-Score ({Periods}:{SourceName})"; } diff --git a/quantower/Statistics/Statistics.csproj b/quantower/Statistics/_Statistics.csproj similarity index 89% rename from quantower/Statistics/Statistics.csproj rename to quantower/Statistics/_Statistics.csproj index 402cf09d..0652872a 100644 --- a/quantower/Statistics/Statistics.csproj +++ b/quantower/Statistics/_Statistics.csproj @@ -1,5 +1,6 @@  + Statistics Indicator bin\$(Configuration)\ true @@ -14,7 +15,7 @@ - + ..\..\.github\TradingPlatform.BusinessLayer.dll diff --git a/quantower/Volatility/AtrIndicator.cs b/quantower/Volatility/AtrIndicator.cs index 1d79ffff..fb2667ad 100644 --- a/quantower/Volatility/AtrIndicator.cs +++ b/quantower/Volatility/AtrIndicator.cs @@ -1,24 +1,41 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class AtrIndicator : IndicatorBarBase +public class AtrIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 20; + [InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)] + public int Periods { get; set; } = 20; private Atr? atr; - protected override AbstractBase QuanTAlib => atr!; - public override string ShortName => $"ATR {Period}"; + protected LineSeries? AtrSeries; + public int MinHistoryDepths => 2; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public AtrIndicator() { Name = "ATR - Average True Range"; Description = "Measures market volatility by calculating the average range between high and low prices."; SeparateWindow = true; + + AtrSeries = new("ATR", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(AtrSeries); } - protected override void InitIndicator() + protected override void OnInit() { - atr = new(Period); - MinHistoryDepths = atr!.WarmupPeriod; + atr = new Atr(Periods); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TBar input = IndicatorExtensions.GetInputBar(this, args); + TValue result = atr!.Calc(input); + + AtrSeries!.SetValue(result.Value); + } + + public override string ShortName => $"ATR ({Periods})"; } diff --git a/quantower/Volatility/HistoricalIndicator.cs b/quantower/Volatility/HistoricalIndicator.cs index 8465714f..06ed5ec8 100644 --- a/quantower/Volatility/HistoricalIndicator.cs +++ b/quantower/Volatility/HistoricalIndicator.cs @@ -1,29 +1,44 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class HistoricalIndicator : IndicatorBase +public class HistoricalIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 20; + [InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)] + public int Periods { get; set; } = 20; [InputParameter("Annualized", sortIndex: 2)] public bool IsAnnualized { get; set; } = true; private Historical? historical; - protected override AbstractBase QuanTAlib => historical!; - public override string ShortName => $"Historical Volatility {Period}{(IsAnnualized ? " - Annualized" : "")} : {SourceName}"; + protected LineSeries? HvSeries; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public HistoricalIndicator() : base() + public HistoricalIndicator() { Name = "HV - Historical Volatility"; Description = "Measures price fluctuations over time, indicating market volatility based on past price movements."; SeparateWindow = true; + + HvSeries = new("HV", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(HvSeries); } - protected override void InitIndicator() + protected override void OnInit() { - historical = new(Period, IsAnnualized); - MinHistoryDepths = historical.WarmupPeriod; - base.InitIndicator(); + historical = new Historical(Periods, IsAnnualized); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TBar input = IndicatorExtensions.GetInputBar(this, args); + TValue result = historical!.Calc(input); + + HvSeries!.SetValue(result.Value); + } + + public override string ShortName => $"HV ({Periods}{(IsAnnualized ? " - Annualized" : "")})"; } diff --git a/quantower/Volatility/RealizedIndicator.cs b/quantower/Volatility/RealizedIndicator.cs index 86d7e000..126658c7 100644 --- a/quantower/Volatility/RealizedIndicator.cs +++ b/quantower/Volatility/RealizedIndicator.cs @@ -1,29 +1,44 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class RealizedIndicator : IndicatorBase +public class RealizedIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] - public int Period { get; set; } = 20; + [InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)] + public int Periods { get; set; } = 20; [InputParameter("Annualized", sortIndex: 2)] public bool IsAnnualized { get; set; } = true; private Realized? realized; - protected override AbstractBase QuanTAlib => realized!; - public override string ShortName => $"Realized Volatility {Period}{(IsAnnualized ? " - Annualized" : "")} : {SourceName}"; + protected LineSeries? RvSeries; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public RealizedIndicator() : base() + public RealizedIndicator() { Name = "RV - Realized Volatility"; Description = "Measures actual price volatility over a specific period, useful for risk assessment and forecasting."; SeparateWindow = true; + + RvSeries = new("RV", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(RvSeries); } - protected override void InitIndicator() + protected override void OnInit() { - realized = new(Period, IsAnnualized); - MinHistoryDepths = realized.WarmupPeriod; - base.InitIndicator(); + realized = new Realized(Periods, IsAnnualized); + base.OnInit(); } + + protected override void OnUpdate(UpdateArgs args) + { + TBar input = IndicatorExtensions.GetInputBar(this, args); + TValue result = realized!.Calc(input); + + RvSeries!.SetValue(result.Value); + } + + public override string ShortName => $"RV ({Periods}{(IsAnnualized ? " - Annualized" : "")})"; } diff --git a/quantower/Volatility/RviIndicator.cs b/quantower/Volatility/RviIndicator.cs index 9c8de27d..005ae679 100644 --- a/quantower/Volatility/RviIndicator.cs +++ b/quantower/Volatility/RviIndicator.cs @@ -1,26 +1,41 @@ +using System.Drawing; using TradingPlatform.BusinessLayer; + namespace QuanTAlib; -public class RviIndicator : IndicatorBase +public class RviIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Period", sortIndex: 1, 2, 100, 1, 0)] - public int Period { get; set; } = 10; + [InputParameter("Periods", sortIndex: 1, 2, 100, 1, 0)] + public int Periods { get; set; } = 10; private Rvi? rvi; - protected override AbstractBase QuanTAlib => rvi!; - public override string ShortName => $"RVI {Period} : {SourceName}"; + protected LineSeries? RviSeries; + public int MinHistoryDepths => Periods; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; - public RviIndicator() : base() + public RviIndicator() { Name = "RVI - Relative Volatility Index"; Description = "Measures the direction of volatility, helping to identify overbought or oversold conditions in price."; SeparateWindow = true; - } - protected override void InitIndicator() - { - rvi = new Rvi(Period); - MinHistoryDepths = rvi.WarmupPeriod; - base.InitIndicator(); + RviSeries = new("RVI", Color.Blue, 2, LineStyle.Solid); + AddLineSeries(RviSeries); } + + protected override void OnInit() + { + rvi = new Rvi(Periods); + base.OnInit(); + } + + protected override void OnUpdate(UpdateArgs args) + { + TBar input = IndicatorExtensions.GetInputBar(this, args); + TValue result = rvi!.Calc(input); + + RviSeries!.SetValue(result.Value); + } + + public override string ShortName => $"RVI ({Periods})"; } diff --git a/quantower/Volatility/TestIndicator.cs b/quantower/Volatility/TestIndicator.cs new file mode 100644 index 00000000..aad1dfda --- /dev/null +++ b/quantower/Volatility/TestIndicator.cs @@ -0,0 +1,66 @@ +using System.Drawing; +using TradingPlatform.BusinessLayer; + +namespace QuanTAlib; + +public class TestIndicator : Indicator, IWatchlistIndicator +{ + [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] + public int Period { get; set; } = 10; + + [InputParameter("Data source", sortIndex: 20, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + + private Sma? ma; + protected LineSeries? Series; + //protected string? SourceName; + public int MinHistoryDepths { get; set; } + int IWatchlistIndicator.MinHistoryDepths => 0; //QuanTAlib indicators generate value immediately + + + public TestIndicator() + { + OnBackGround = true; + SeparateWindow = false; + Name = "TEST"; + Description = "test and test and test and more test."; + Series = new(name: $"{Name}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); + } + + protected override void OnInit() + { + ma = new Sma(Period); + base.OnInit(); + } + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + TValue result = ma!.Calc(input); + + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here + Series!.SetValue(result); + } + + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } +} + diff --git a/quantower/Volatility/Volatility.csproj b/quantower/Volatility/_Volatility.csproj similarity index 89% rename from quantower/Volatility/Volatility.csproj rename to quantower/Volatility/_Volatility.csproj index 3b829bd6..4edad8ee 100644 --- a/quantower/Volatility/Volatility.csproj +++ b/quantower/Volatility/_Volatility.csproj @@ -1,5 +1,6 @@  + Volatility Indicator bin\$(Configuration)\ true @@ -14,7 +15,8 @@ - + + ..\..\.github\TradingPlatform.BusinessLayer.dll diff --git a/quantower/_IndicatorBarBase.cs b/quantower/_IndicatorBarBase.cs deleted file mode 100644 index 47bbcc1b..00000000 --- a/quantower/_IndicatorBarBase.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System.Drawing; -using TradingPlatform.BusinessLayer; -using TradingPlatform.BusinessLayer.Chart; -using System.Runtime.CompilerServices; -using System.Drawing.Drawing2D; -using System.Collections; -using TradingPlatform.BusinessLayer.TimeSync; - -namespace QuanTAlib; - -#pragma warning disable CA1416 // Validate platform compatibility -public abstract class IndicatorBarBase : Indicator, IWatchlistIndicator -{ - - [InputParameter("Show cold values", sortIndex: 20)] - public bool ShowColdValues { get; set; } = true; - public int MinHistoryDepths { get; set; } - - // LineSeries.LineSeries(string, Color, int, LineStyle)' - - protected LineSeries? Series; - protected abstract AbstractBase QuanTAlib { get; } - - int IWatchlistIndicator.MinHistoryDepths => 0; - - protected IndicatorBarBase() - { - OnBackGround = true; - SeparateWindow = false; - Series = new(name: $"{Name}", color: Color.RoyalBlue, width: 2, style: LineStyle.Solid); - - AddLineSeries(Series); - } - - protected abstract void InitIndicator(); - - protected override void OnInit() - { - InitIndicator(); - base.OnInit(); - } - - protected override void OnUpdate(UpdateArgs args) - { - TBar bar = new(Time: Time(), - Open: GetPrice(PriceType.Open), - High: GetPrice(PriceType.High), - Low: GetPrice(PriceType.Low), - Close: GetPrice(PriceType.Close), - Volume: GetPrice(PriceType.Volume), - IsNew: args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar); - - TValue result = QuanTAlib.Calc(bar); - Series!.SetValue(result.Value); - Series!.SetMarker(0, Color.Transparent); - - } - - public override void OnPaintChart(PaintChartEventArgs args) - { - base.OnPaintChart(args); - List allPoints = new List(); - if (CurrentChart == null) { return; } - - Graphics gr = args.Graphics; - - var mainWindow = this.CurrentChart.Windows[args.WindowIndex]; - var converter = mainWindow.CoordinatesConverter; - var clientRect = mainWindow.ClientRectangle; - - gr.SetClip(clientRect); - DateTime leftTime = new[] { converter.GetTime(clientRect.Left), Time(this.Count - 1) }.Max(); - DateTime rightTime = new[] { converter.GetTime(clientRect.Right), Time(0) }.Min(); - - int leftIndex = (int)HistoricalData.GetIndexByTime(leftTime.Ticks) + 1; - int rightIndex = (int)HistoricalData.GetIndexByTime(rightTime.Ticks); - - for (int i = rightIndex; i < leftIndex; i++) - { - int barX = (int)converter.GetChartX(Time(i)); - int barY = (int)converter.GetChartY(Series![i]); - int halfBarWidth = CurrentChart.BarsWidth / 2; - Point point = new(barX + halfBarWidth, barY); - allPoints.Add(point); - } - - if (allPoints.Count > 1) - { - DrawSmoothCombinedCurve(gr, allPoints, this.Count - QuanTAlib.WarmupPeriod - rightIndex); - } - } - - private void DrawSmoothCombinedCurve(Graphics gr, List allPoints, int hotCount) - { - if (allPoints.Count < 2) { return; } - - using Pen defaultPen = new(Series!.Color, Series.Width) { DashStyle = ConvertLineStyleToDashStyle(Series.Style) }; - using Pen coldPen = new(Series!.Color, Series.Width) { DashStyle = DashStyle.Dot }; - - // Draw the hot part - if (hotCount > 0) - { - var hotPoints = allPoints.Take(Math.Min(hotCount + 1, allPoints.Count)).ToArray(); - gr.DrawCurve(defaultPen, hotPoints, 0, hotPoints.Length - 1, (float)0.1); - } - - // Draw the cold part - if (ShowColdValues && hotCount < allPoints.Count) - { - var coldPoints = allPoints.Skip(Math.Max(0, hotCount)).ToArray(); - gr.DrawCurve(coldPen, coldPoints, 0, coldPoints.Length - 1, (float)0.1); - } - } - private static DashStyle ConvertLineStyleToDashStyle(LineStyle lineStyle) - { - return lineStyle switch - { - LineStyle.Solid => DashStyle.Solid, - LineStyle.Dash => DashStyle.Dash, - LineStyle.Dot => DashStyle.Dot, - LineStyle.DashDot => DashStyle.DashDot, - _ => DashStyle.Solid, - }; - } - protected static void DrawText(Graphics gr, string text, Rectangle clientRect) - { - Font font = new("Inter", 8); - SizeF textSize = gr.MeasureString(text, font); - RectangleF textRect = new(clientRect.Left + 5, - clientRect.Bottom - textSize.Height - 10, - textSize.Width + 10, textSize.Height + 10); - gr.FillRectangle(SystemBrushes.ControlDarkDark, textRect); - gr.DrawString(text, font, Brushes.White, new PointF(textRect.X + 6, textRect.Y + 5)); - } -} \ No newline at end of file diff --git a/quantower/_IndicatorBase.cs b/quantower/_IndicatorBase.cs deleted file mode 100644 index 37d70d06..00000000 --- a/quantower/_IndicatorBase.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System.Drawing; -using TradingPlatform.BusinessLayer; -using TradingPlatform.BusinessLayer.Chart; -using System.Runtime.CompilerServices; -using System.Drawing.Drawing2D; -using System.Collections; -using TradingPlatform.BusinessLayer.TimeSync; - -namespace QuanTAlib; - -#pragma warning disable CA1416 // Validate platform compatibility -public abstract class IndicatorBase : Indicator, IWatchlistIndicator -{ - - [InputParameter("Data source", sortIndex: 17, variants: [ - "Open", 1, - "High", 2, - "Low", 3, - "Close", 4, - "HL/2 (Median)", 5, - "OC/2 (Midpoint)", 6, - "OHL/3 (Mean)", 7, - "HLC/3 (Typical)", 8, - "OHLC/4 (Average)", 9, - "HLCC/4 (Weighted)", 10 - ])] - public int Source { get; set; } = 4; - - [InputParameter("Show cold values", sortIndex: 20)] - public bool ShowColdValues { get; set; } = true; - public int MinHistoryDepths { get; set; } - - // LineSeries.LineSeries(string, Color, int, LineStyle)' - - protected LineSeries? Series; - protected string SourceName; - protected abstract AbstractBase QuanTAlib { get; } - - int IWatchlistIndicator.MinHistoryDepths => 0; - - protected IndicatorBase() - { - OnBackGround = true; - SeparateWindow = false; - SourceName = GetName(Source); - Series = new(name: $"{Name}", color: Color.Yellow, width: 2, style: LineStyle.Solid); - - AddLineSeries(Series); - } - - protected virtual void InitIndicator() - { - SourceName = GetName(Source); - } - - protected override void OnInit() - { - InitIndicator(); - base.OnInit(); - } - - protected override void OnUpdate(UpdateArgs args) - { - TBar bar = new(Time: Time(), - Open: GetPrice(PriceType.Open), - High: GetPrice(PriceType.High), - Low: GetPrice(PriceType.Low), - Close: GetPrice(PriceType.Close), - Volume: GetPrice(PriceType.Volume), - IsNew: args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar); - - double price = Source switch - { - 1 => bar.Open, - 2 => bar.High, - 3 => bar.Low, - 4 => bar.Close, - 5 => bar.HL2, - 6 => bar.OC2, - 7 => bar.OHL3, - 8 => bar.HLC3, - 9 => bar.OHLC4, - 10 => bar.HLCC4, - _ => bar.Close - }; - - TValue input = new TValue(bar.Time, price, bar.IsNew); - TValue result = QuanTAlib.Calc(input); - Series!.SetValue(result.Value); - Series!.SetMarker(0, Color.Transparent); - - } - - public override void OnPaintChart(PaintChartEventArgs args) - { - base.OnPaintChart(args); - List allPoints = new List(); - if (CurrentChart == null) { return; } - - Graphics gr = args.Graphics; - var mainWindow = this.CurrentChart.Windows[args.WindowIndex]; - var converter = mainWindow.CoordinatesConverter; - var clientRect = mainWindow.ClientRectangle; - - gr.SetClip(clientRect); - DateTime leftTime = new[] { converter.GetTime(clientRect.Left), Time(this.Count - 1) }.Max(); - DateTime rightTime = new[] { converter.GetTime(clientRect.Right), Time(0) }.Min(); - - int leftIndex = (int)HistoricalData.GetIndexByTime(leftTime.Ticks) + 1; - int rightIndex = (int)HistoricalData.GetIndexByTime(rightTime.Ticks); - - for (int i = rightIndex; i < leftIndex; i++) - { - int barX = (int)converter.GetChartX(Time(i)); - int barY = (int)converter.GetChartY(Series![i]); - int halfBarWidth = CurrentChart.BarsWidth / 2; - Point point = new Point(barX + halfBarWidth, barY); - allPoints.Add(point); - } - - if (allPoints.Count > 1) - { - DrawSmoothCombinedCurve(gr, allPoints, this.Count - QuanTAlib.WarmupPeriod - rightIndex); - } - } - - private void DrawSmoothCombinedCurve(Graphics gr, List allPoints, int hotCount) - { - if (allPoints.Count < 2) { return; } - - using (Pen defaultPen = new(Series!.Color, Series.Width) { DashStyle = ConvertLineStyleToDashStyle(Series.Style) }) - using (Pen coldPen = new(Series!.Color, Series.Width) { DashStyle = DashStyle.Dot }) - { - // Draw the hot part - if (hotCount > 0) - { - var hotPoints = allPoints.Take(Math.Min(hotCount + 1, allPoints.Count)).ToArray(); - gr.DrawCurve(defaultPen, hotPoints, 0, hotPoints.Length - 1, (float)0.2); - } - - // Draw the cold part - if (ShowColdValues && hotCount < allPoints.Count) - { - var coldPoints = allPoints.Skip(Math.Max(0, hotCount)).ToArray(); - gr.DrawCurve(coldPen, coldPoints, 0, coldPoints.Length - 1, (float)0.2); - } - } - } - private DashStyle ConvertLineStyleToDashStyle(LineStyle lineStyle) - { - return lineStyle switch - { - LineStyle.Solid => DashStyle.Solid, - LineStyle.Dash => DashStyle.Dash, - LineStyle.Dot => DashStyle.Dot, - LineStyle.DashDot => DashStyle.DashDot, - _ => DashStyle.Solid, - }; - } - protected void DrawText(Graphics gr, string text, Rectangle clientRect) - { - Font font = new Font("Inter", 8); - SizeF textSize = gr.MeasureString(text, font); - RectangleF textRect = new RectangleF(clientRect.Left + 5, - clientRect.Bottom - textSize.Height - 10, - textSize.Width + 10, textSize.Height + 10); - gr.FillRectangle(SystemBrushes.ControlDarkDark, textRect); - gr.DrawString(text, font, Brushes.White, new PointF(textRect.X + 6, textRect.Y + 5)); - } - protected string GetName(int pType) - { - return pType switch - { - 1 => "Open", - 2 => "High", - 3 => "Low", - 4 => "Close", - 5 => "Median", - 6 => "Midpoint", - 7 => "Mean", - 8 => "Typical", - 9 => "Average", - 10 => "Weighted", - _ => "N/A" - }; - } - -} \ No newline at end of file