I have placed the .DLL for this library in the directory
but it does not show up in Assemblies. Unlike my previous problem with MathNet (https://www.wealth-lab.com/Discussion/MathNet-Numerics-doesn-t-show-up-in-Assemblies-12412) I cannot access it at all from my program. Cone's suggestion about un-blocking does not seem to be the issue. I have used the netstandard2.0 version of the DLL if that matters.
What am I doing wrong?
QUOTE:
C:\Program Files\Quantacula, LLC\WealthLab 8
but it does not show up in Assemblies. Unlike my previous problem with MathNet (https://www.wealth-lab.com/Discussion/MathNet-Numerics-doesn-t-show-up-in-Assemblies-12412) I cannot access it at all from my program. Cone's suggestion about un-blocking does not seem to be the issue. I have used the netstandard2.0 version of the DLL if that matters.
What am I doing wrong?
Rename
QUOTE:
but it does not show up in Assemblies.
Your question is incomplete. Are you saying ...
1) It does not show up in the Visual Studio IDE or
2) it does not show up for WL8 Strategy execution?
In both cases, you need to set file assembly references to locate the .DLL, but it's done differently for different applications. In WL8, you need to use the
"Tools >> Assembly References" menu item to declare the .DLL file location.
superticker,
Good point. Yes, this is WL8 and I have copied the DLL and then looked for the Assembly Reference in the Tools menu after restarting WL8. It is not there. 😣 I am not sure what else might be required. The help menu says that is all that is needed. Obviously I am doing something wrong.
Good point. Yes, this is WL8 and I have copied the DLL and then looked for the Assembly Reference in the Tools menu after restarting WL8. It is not there. 😣 I am not sure what else might be required. The help menu says that is all that is needed. Obviously I am doing something wrong.
Doesn't Dr. Koch's response in post 3 help resolve it from your previous discussion? In short, it doesn't need to show in Tools > Assys. Just make the reference and use it.
Cone,
Tried that. No luck, unfortunately this time.
Tried that. No luck, unfortunately this time.
It works for me. I fetched NWaves 0.9.6 via nuget, and copied the .NET Standard NWaves.DLL and NWaves.xml files to the WealthLab executable folder. I restarted WL8. The WL8 assembly references dialog does not show NWaves in its list. Anyhow, I am able to reference NWaves from a C# strategy and create a ComplexDiscreteSignal and reference its members...
Check that NWaves.dll is actually in the WealthLab folder (I suppose it is from your original post).
Perhaps the problem is not fully qualifying the reference or using appropriate using(s).
CODE:
var cds = new NWaves.Signals.ComplexDiscreteSignal(5, 5, 8.0, 3.2); WriteToDebugLog(cds.Length);
Check that NWaves.dll is actually in the WealthLab folder (I suppose it is from your original post).
Perhaps the problem is not fully qualifying the reference or using appropriate using(s).
paul1986,
You mentioned something I did not do...add the XML file. I did that but it did not help. WL8 is not recognizing NWaves since I am getting all manner of error when I do a Compile.
I have the following using statements:
using NWaves;
using NWaves.Transforms;
using NWaves.Filters;
using NWaves.Signals;
But still no luck.
You mentioned something I did not do...add the XML file. I did that but it did not help. WL8 is not recognizing NWaves since I am getting all manner of error when I do a Compile.
I have the following using statements:
using NWaves;
using NWaves.Transforms;
using NWaves.Filters;
using NWaves.Signals;
But still no luck.
QUOTE:
WL8 is not recognizing NWaves since I am getting all manner of error when I do a Compile.
Please post the errors.
Here is one example:
Compiled at 6/29/2025 09:59:32
345: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
190: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
191: The type or namespace name 'Fwt' could not be found (are you missing a using directive or an assembly reference?)
222: The type or namespace name 'Fwt' could not be found (are you missing a using directive or an assembly reference?)
349: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
351: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
353: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
355: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
382: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
384: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
Compiled at 6/29/2025 09:59:32
345: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
190: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
191: The type or namespace name 'Fwt' could not be found (are you missing a using directive or an assembly reference?)
222: The type or namespace name 'Fwt' could not be found (are you missing a using directive or an assembly reference?)
349: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
351: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
353: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
355: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
382: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
384: The type or namespace name 'Wavelet' could not be found (are you missing a using directive or an assembly reference?)
Sounds to me like you have a namespace problem. The following works for me:
CODE:
using NWaves.Transforms.Wavelets; // then in method Initialize()... var wv = new Wavelet(WaveletFamily.Coiflet);
paul1986,
You were correct! I had "using NWaves.Transforms;" rather that the correct directive "using NWaves.Transforms.Wavelets;" with the very mistaken idea that the former would be able to access it.
Thank you so very much for taking the time to solve my problem. Much appreciated!
You were correct! I had "using NWaves.Transforms;" rather that the correct directive "using NWaves.Transforms.Wavelets;" with the very mistaken idea that the former would be able to access it.
Thank you so very much for taking the time to solve my problem. Much appreciated!
QUOTE:
You were correct! I had "using NWaves.Transforms;" rather that the correct directive "using NWaves.Transforms.Wavelets;" with the very mistaken idea that the former would be able to access it.
I've been looking at the code. https://github.com/ar1st0crat/NWaves/blob/master/NWaves/Transforms/Wavelets/Fwt.cs
I'm wondering if the author was expecting you to include "using NWaves.Transforms;" and then prefix the individual methods with "Wavelets."
CODE:so they don't get confused with other method names in the NWaves library. But if you're only going to use a specific portion of the NWaves library, this confusion shouldn't be an issue.
var signal = new Wavelets.Fwt(...);
I have a LOT to learn about C# (obviously)! 🙄
@Carova: Now that the NWaves digital signal processing (DSP) library is working for you, I am curious to learn what you are trying to do with this.
I come from a DSP background and over the years I tried many DSP ideas in trading systems. (With not much success.)
DSP algorithms are usually designed for linear, time invariant (LTI) problems whereas time series are random walks with varying volatility.
Of course it helps to use the first derivatve i.e. the rate of change (ROC) but here the distribution is not tame as required by most DSP algorithms, i.e. we have fat tails / outliers that disturb most resuöts heavily.
So, please let me know about your ideas...
I come from a DSP background and over the years I tried many DSP ideas in trading systems. (With not much success.)
DSP algorithms are usually designed for linear, time invariant (LTI) problems whereas time series are random walks with varying volatility.
Of course it helps to use the first derivatve i.e. the rate of change (ROC) but here the distribution is not tame as required by most DSP algorithms, i.e. we have fat tails / outliers that disturb most resuöts heavily.
So, please let me know about your ideas...
DrKock,
You are quite correct about the issues associated with the basic time series behaviors being a very poor match for typical DSP algorithms for the very reasons you mentioned. However, I might suggest that you also take a page out of you previous DSP experience and consider both potential clever coordinate transformations and operations that significantly alter the characteristics of the time series. Doing that makes the data much more amenable to some limited traditional DSP approaches.
You are quite correct about the issues associated with the basic time series behaviors being a very poor match for typical DSP algorithms for the very reasons you mentioned. However, I might suggest that you also take a page out of you previous DSP experience and consider both potential clever coordinate transformations and operations that significantly alter the characteristics of the time series. Doing that makes the data much more amenable to some limited traditional DSP approaches.
QUOTE:
consider ... potential clever coordinate transformations ... that significantly alter the characteristics of the time series.
Can you give us an example? I can't imagine what kind of coordinate transformation would clarify this kind of time series problem.
superticker,
The most obvious one...a simple log transformation.
The most obvious one...a simple log transformation.
I paraphrased Carova's statement, asking Microsoft CoPilot:
Copilot came back with a bevy of info. Then it suggested to apply it to financial time series analysis, and then it gave a whole bunch more info. Then Copilot:
I said yes, and of course gave a bunch more info. I told it I wanted it to build out a specific strategy template for Wealth-Lab 8. And, it did within about 1 second.
So, rather than post the conversation here, its lengthy, I suggest striking up a conversation with your favorite AI. Neat stuff.
QUOTE:
Basic time series behaviors are a very poor match for typical DSP algorithms. However, consider both potential clever coordinate transformations and operations that significantly alter the characteristics of the time series. Doing that makes the data much more amenable to some limited traditional DSP approaches. Can you elaborate?
Copilot came back with a bevy of info. Then it suggested to apply it to financial time series analysis, and then it gave a whole bunch more info. Then Copilot:
QUOTE:
If you're experimenting with this inside Wealth-Lab 8 or integrating it into Thinkscript models, you could use transformed signals as precursors for divergence detection or cross-signal convergence strategies. Want to sketch one out?
I said yes, and of course gave a bunch more info. I told it I wanted it to build out a specific strategy template for Wealth-Lab 8. And, it did within about 1 second.
So, rather than post the conversation here, its lengthy, I suggest striking up a conversation with your favorite AI. Neat stuff.
QUOTE:
use transformed signals as precursors for divergence detection or cross-signal convergence strategies.
I'm not sure transformed signals for divergence is that helpful. But cross-signal convergence strategies sounds interesting. If you could post the WL code it generated, I would be interested.
QUOTE:
I'm not sure transformed signals for divergence is that helpful. But cross-signal convergence strategies sounds interesting. If you could post the WL code it generated, I would be interested.
MS Copilot generated an outline of what to do in code. Then I told it, give me the code. It did. I popped the code into JetBrains Rider where I use the GitHub Copilot plugin. The generated code needed some coaxing to get it to compile, but eventually it came up with the following. (The coaxing was only to get the code to compile without error, and allowing WL parameters to be used.) I really don't know anything about DSP. This was just an exercise in using AI and exploring DSP.
CODE:
using System; using System.Linq; using NWaves.Filters.Bessel; using NWaves.Signals; using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthLabStrategies.MovingAverage { /// <summary> /// Implements a cycle divergence strategy using band-pass filtering and RSI on price data. /// </summary> public class CycleDivergence : UserStrategyBase { // Parameter index constants private const int VolPeriodIdx = 0; private const int RsiPeriodIdx = 1; private const int BpLowIdx = 2; private const int BpHighIdx = 3; private const int RsiCrossIdx = 4; private const int RsiCrossUnderIdx = 5; private TimeSeries _logClose, _logReturn, _volatility, _cumVol; private double _rsiCrossUnderValue; private double _rsiCrossValue; private TimeSeries _rsiRaw, _rsiFiltered, _dspFiltered, _lrSlope; public CycleDivergence() { AddParameter("Volatility Lookback", ParameterType.Int32, 20, 5, 50, 5); AddParameter("RSI Period", ParameterType.Int32, 14, 5, 30); AddParameter("BandPass Low", ParameterType.Double, 0.05, 0.01, 0.2, 0.01); AddParameter("BandPass High", ParameterType.Double, 0.15, 0.05, 0.5, 0.01); AddParameter("RSI Crossover", ParameterType.Double, 30.0, 10.0, 50.0); AddParameter("RSI Crossunder", ParameterType.Double, 70.0, 50.0, 90.0); // New parameter } public override void Initialize(BarHistory bars) { var volPeriod = Parameters[VolPeriodIdx].AsInt; var rsiPeriod = Parameters[RsiPeriodIdx].AsInt; var bpLow = (float) Parameters[BpLowIdx].AsDouble; var bpHigh = (float) Parameters[BpHighIdx].AsDouble; _rsiCrossValue = Parameters[RsiCrossIdx].AsDouble; _rsiCrossUnderValue = Parameters[RsiCrossUnderIdx].AsDouble; // Get cross under value // Step 1: Log of Close prices _logClose = new TimeSeries(bars.DateTimes); for (var i = 0; i < bars.Count; i++) { _logClose[i] = Math.Log(bars.Close[i]); } // Step 2: Log returns _logReturn = new TimeSeries(bars.DateTimes) { [0] = 0.0 }; for (var i = 1; i < bars.Count; i++) { _logReturn[i] = _logClose[i] - _logClose[i - 1]; } // Step 3: Volatility estimate _volatility = StdDev.Series(_logReturn, volPeriod); _cumVol = new TimeSeries(bars.DateTimes) { [0] = _volatility[0] }; for (var i = 1; i < bars.Count; i++) { _cumVol[i] = _cumVol[i - 1] + _volatility[i]; } // Step 4: Convert to NWaves signal var signalArray = new float[bars.Count]; for (var i = 0; i < bars.Count; i++) { signalArray[i] = (float) _logReturn[i]; } var signal = new DiscreteSignal(1, signalArray); // Step 5: Apply NWaves band-pass filter var bpFilter = new BandPassFilter(bpLow, bpHigh, 4); var filtered = bpFilter.ApplyTo(signal); // Step 6: Convert back to TimeSeries, align with bars.Count var filteredSamples = filtered.Samples.ToArray(); _dspFiltered = new TimeSeries(bars.DateTimes); var pad = bars.Count - filteredSamples.Length; for (var i = 0; i < bars.Count; i++) { _dspFiltered[i] = i < pad ? 0.0 : filteredSamples[i - pad]; } // Step 7: RSI calculations _rsiRaw = RSI.Series(bars.Close, rsiPeriod); _rsiFiltered = RSI.Series(_dspFiltered, rsiPeriod); // Step 8: LRSlope calculation (window size 3 to match previous logic) _lrSlope = LRSlope.Series(_dspFiltered, 3); // Plot each TimeSeries in its own pane (without "Pane" in the pageTag) PlotTimeSeries(_rsiRaw, "RSI Raw", "RSI Raw"); PlotTimeSeries(_rsiFiltered, "RSI Filtered", "RSI Filtered"); PlotTimeSeries(_dspFiltered, "Filtered Signal", "Filtered Signal"); PlotTimeSeries(_lrSlope, "LR Slope", "LR Slope"); // Set StartIndex to the maximum lookback required by any indicator or logic var maxLookback = Math.Max( Math.Max(volPeriod, rsiPeriod), 5 // for the 5-bar lookback in Execute ); StartIndex = maxLookback; } public override void Execute(BarHistory bars, int idx) { var openPos = FindOpenPosition(PositionType.Long); if (openPos != null) { var slopeNegative = _lrSlope[idx] < 0; if (_rsiFiltered.CrossesUnder(_rsiCrossUnderValue, idx) || slopeNegative) { ClosePosition(openPos, OrderType.Market, 0, "Exit on RSI or slope condition"); } return; } var lowerLow = bars.Close[idx] < bars.Close[idx - 5]; var higherRsi = _rsiFiltered[idx] > _rsiFiltered[idx - 5]; if (lowerLow && higherRsi && _rsiFiltered.CrossesOver(_rsiCrossValue, idx)) { PlaceTrade(bars, TransactionType.Buy, OrderType.Market, 0, "Buy"); } } } }
If you are looking at a somewhat more sophisticated transformation, consider the Box Transform. This takes a bit more effort to establish the best lambda, but it does work well for MOST US equity series. You will find some series will need to be thrown out unfortunately.
BTW, you would really need to be an "ol' timer" to even remember this one! 😁
BTW, you would really need to be an "ol' timer" to even remember this one! 😁
Thank you both for the info. I'll take a closer look once I have my WL6 to WL8 conversion all done. I don't even know what a Box Transform is. I'll have to investigate that.
super,
You are a youngin' so I am not surprised you had not heard of the Box Transform. 😉😉 I am guessing it was developed during the 50's/60's when there was a huge number of developments in statistics by some very smart folk.
You are a youngin' so I am not surprised you had not heard of the Box Transform. 😉😉 I am guessing it was developed during the 50's/60's when there was a huge number of developments in statistics by some very smart folk.
QUOTE:
If you are looking at a somewhat more sophisticated transformation, consider the Box Transform. This takes a bit more effort to establish the best lambda, but it does work well for MOST US equity series.
I was curious what GitHub Copilot thought of that with respect to the strategy in Post #19. I asked it several questions, below. The reasons it stated are rather lengthy, so I didn't post them here.
QUOTE:
Does it make sense to introduce the use of Box-Cox transform? No.
QUOTE:
Would it make sense to have a different strategy that utilizes the Box-Cox transform? No.
QUOTE:
Then, using the current strategy, does it make sense to determine an optimized lambda? No.
QUOTE:
Forget about using Box-Cox transform for the current strategy. Does it make sense to use log transformation of the current strategy but with a different lambda? No. So, here it summed it up:
The log transformation is mathematically defined as the Box-Cox transform with λ = 0.
Using a "log transformation with a different lambda" is not meaningful; if you change lambda, you are no longer using a log transform, but a different Box-Cox transformation.
In financial time series, the log transform (λ = 0) is standard because it stabilizes variance and handles multiplicative effects naturally.
Other lambda values are rarely used in trading strategies unless there is a specific, data-driven reason to do so.
Thanks paul1986!
From GitHub CoPilot:
I suggest that you pay attention to this statement.
From GitHub CoPilot:
QUOTE:
unless there is a specific, data-driven reason to do so
I suggest that you pay attention to this statement.
Keep in mind, I'm a big dummy about this, so I asked GitHub Copilot:
It answered:
QUOTE:
You stated: "Other lambda values are rarely used in trading strategies unless there is a specific, data-driven reason to do so." Can you give me an example of a specific data-driven reason?
It answered:
QUOTE:
A specific data-driven reason to use a Box-Cox transform with a lambda other than 0 (log) or 1 (no transform) would be if, after analyzing your data, you find that the distribution of your returns or indicator values is highly skewed or exhibits non-constant variance (heteroscedasticity) that is not adequately addressed by the log transform.
Example scenario: Suppose you perform a statistical analysis (such as plotting histograms, Q-Q plots, or calculating skewness/kurtosis) on your returns or indicator values and find:
The data remains significantly skewed or non-normal after log transformation.
The variance of your series changes with the level of the series (e.g., higher values have much higher variance).
You could then use a Box-Cox transformation and optimize lambda (using maximum likelihood estimation or minimizing skewness) to find the value that best normalizes your data and stabilizes variance. This might improve the performance of statistical models or machine learning algorithms that assume normality or homoscedasticity.
In summary:
A data-driven reason would be:
You empirically determine, through statistical tests or visualizations, that a different lambda provides a distribution closer to normality or more stable variance than the log transform, and this improves the performance or robustness of your trading model.
Your Response
Post
Edit Post
Login is required