Use second plot as input ?

Spin

Well-known member
Joined
May 22, 2019
Posts
477
Likes
191
Hello there fellow coders :)

It's been a while that I launched a thread of my own, but I am afraid the time has come. Again :D

I am looking to use the 'values' or 'data' from a secondary plot to use in calculations.
More specifically, I would like to add fractals to a second Study
Fractals are calculated like so:
Java:
List<SwingPoint> swingPoints = series.calcSwingPoints(getSettings().getInteger(Inputs.STRENGTH, 2));

so I need to create a secondary series that holds the data from a 'Study B'
OR
I need to figure out a way to use calcSwingPoints on the data/values of Study B (Study B stores floats for Open, High, Low, Close to the dataseries)

Did anyone on this expert forum try something similar before ?
What would be a good way to tackle this ?

Thanks for all hints, tips & snippets !! (y)
 
Last edited:

Spin

Well-known member
Joined
May 22, 2019
Posts
477
Likes
191
Yep, but it took me several coding hours:
I dove in a few rabbit holes first, to no avail (see below).
And then I realized that good advice that @MotiveWave_Joe once gave me, and put all of the logic into a single study.
https://support.motivewave.com/foru...ing-values-in-a-different-study.273/post-1103

A few of the rabbit holes (that did NOT work):
(I need to add here that Studies A and B both 'live' in a different Plot: A is calculated on Price, B is some sort of oscillator that takes volume into account and is drawn on a secondary plot)

  • tried to create a secondary DataSeries on the primary plot, to hold data from a different Study
    (I don't think this can be done ?)
  • export Values from Study A to DataSeries and import them into Study B
    (apparently each 'window' uses a different DataSeries, although values from both are shown in the Cursor Data Window, seemingly identical; who can shed light onto this ? :unsure:)
  • export Values from Study A to DataSeries and have a 'ulility'-class-method read them from within Study B
    (tried something similar to what STARC-bands does with Bollinger Bands - epic fail, hit the same wall)
  • save Values from Study A to a file and have Study B read them from that file
    (somewhat worked, but laggy)
  • thought of this, but did not try it in the end: store Values from A in a Redis-DB and have B read from it
    (should work imo, and faster too)
But the end result is this:
I drop Study B and have it draw markers on the secondary plot.
I drop Study A, that now holds (part of) the code from Study B, so it calculates the same oscillator / volume thing. Does not draw anything, since I only need the Values.
In Study A I added logic to draw BUY / SELL arrows; this logic uses Values from both Studies A and B.
(sorry for the pixelation; I am not allowed to share details :cool:)
1670011209295.png
 
Last edited:

Per

Active member
Joined
Jun 12, 2021
Posts
28
Likes
7
Yeah that's what I sort of assumed. I had to update one of the indicators and decorate it with something else so I had to do it in one place, like you did.

I think it doesn't yet mean it is impossible, just that we don't know how to. It would be rather sad if this use case isn't covered because it would severely limit complex studies.
 

Spin

Well-known member
Joined
May 22, 2019
Posts
477
Likes
191
I fully agree, @Per !

And since everything is written to the DataSeries anyway, it shouldn't be too hard, no ? :unsure:
 

Dennis

Member
Joined
Oct 30, 2023
Posts
9
Likes
2
Hi there, I might be a little late with my answer, but I found a somewhat usable way of dealing with sharing calculations between studies.

I solved this by creating a singleton class "DataContainer". This container contains a Map where I store my calculations for a given candleIndex. As this is a singleton-pattern, I can reuse this in every study and read from that Map. A Utilty-Class with helper methods allows me to easily write into the series cursorData (eg. series.setXX(..)) and into my map to share the calculations.

This works quite well, but it has one big downside :( I currently can't control the execution order of the studies. My plan is to have multiple studies that calculate something and one big study as a "MasterStudy" that makes decisions based on the calculations of the other studies. But, I can't figure out how to define that the MasterStudy should run after ALL of the other studies finished their calculation. I tried keeping a list of studies that I depend on and having a while-loop in precalculate to wait for the other studies to finish (hoping that the studies are calculated parallel), but that did not work, as the studies are not calculated in parallel, but one after another.

Updating the study with the "Update" Button proves, that my approach is working. I can read the values from the Map. But I don't want to press update all the time, but have the MasterStudy be executed at the last study.

If there only would be a way to define a execution order. That would solve my issue. There is nothing like this documented in the Motivewave SDK javadoc.
 

HalTrader

Active member
Joined
May 26, 2022
Posts
34
Likes
11
Hi there, I might be a little late with my answer, but I found a somewhat usable way of dealing with sharing calculations between studies.

I solved this by creating a singleton class "DataContainer". This container contains a Map where I store my calculations for a given candleIndex. As this is a singleton-pattern, I can reuse this in every study and read from that Map. A Utilty-Class with helper methods allows me to easily write into the series cursorData (eg. series.setXX(..)) and into my map to share the calculations.

This works quite well, but it has one big downside :( I currently can't control the execution order of the studies. My plan is to have multiple studies that calculate something and one big study as a "MasterStudy" that makes decisions based on the calculations of the other studies. But, I can't figure out how to define that the MasterStudy should run after ALL of the other studies finished their calculation. I tried keeping a list of studies that I depend on and having a while-loop in precalculate to wait for the other studies to finish (hoping that the studies are calculated parallel), but that did not work, as the studies are not calculated in parallel, but one after another.

Updating the study with the "Update" Button proves, that my approach is working. I can read the values from the Map. But I don't want to press update all the time, but have the MasterStudy be executed at the last study.

If there only would be a way to define a execution order. That would solve my issue. There is nothing like this documented in the Motivewave SDK javadoc.


I am not a professional programmer, but when you mention about creating a singleton, is it something similar to HashMap, but it is immutable? I did some research, and found a bunch of website that give examples about HashMaps:


Let's say, I have 2 different studies: One of them is RSI (study 1), the other is MACD (study 2). I want to store the last two bars' RSI values in a hashmap, then get these values inside the MACD study.

Java:
import java.util.HashMap;

public class Study1 extends com.motivewave.platform.sdk.study.Study {
    
    // Declare HashMap to store RSI values
    private HashMap<String, Double> rsiValues = new HashMap<>();

    @Override
    public void calculate() {
        // Calculate RSI value for the current bar
        double currentRSI = calculateRSI(); // Replace this with your RSI calculation logic
        
        // Store RSI value of the last bar in the HashMap
        rsiValues.put("lastBarRSI", currentRSI);
        
        // Optionally, store RSI value of the bar preceding the last bar
        double precedingRSI = calculatePrecedingRSI(); // Implement this method to calculate RSI of the preceding bar
        rsiValues.put("precedingBarRSI", precedingRSI);
    }
    
    // Method to retrieve RSI values HashMap
    public HashMap<String, Double> getRSIValues() {
        return rsiValues;
    }
}

And the study 2 should be able to retrieve these HashMap values from the study 1.
Java:
public class Study2 extends com.motivewave.platform.sdk.study.Study {
    
    @Override
    public void calculate() {
        // Get instance of Study 1
        Study1 study1 = (Study1) getContext().getStudy("Study1");
        
        // Retrieve RSI values HashMap from Study 1
        HashMap<String, Double> rsiValues = study1.getRSIValues();
        
        // Get last bar's RSI value
        double lastBarRSI = rsiValues.get("lastBarRSI");
        
        // Optionally, get RSI value of the bar preceding the last bar
        double precedingBarRSI = rsiValues.get("precedingBarRSI");
        
        // Use the retrieved RSI values as needed
    }
}

I used ChatGPT here just to give an example. I get correct hashmap values in study 1, but somehow the study 2 cannot retrieve these values from the study 1. However, even I am successful, this mean that I will have a similar problem like yours, as the calculation time for the study 1 will be different than the study 2, so it won't work?

Otherwise, I was able to export these values into a .csv file (again, only the last 2 bar's RSI values for example, not the whole Data Series), but when the csv file is read by the study 2, it gives an "ArrayIndexOutOfBoundsException" error. Although I did not have any calculation problem, this error was weird, because I verified that the number of Array Elements was less than or equal to the length of the array. Anyway.

I think the best approach would be using Redis or MySQL as @Spin suggested in other posts. But I am bit lazy, since I only want to export last two bar's values from a given study.

I am open to your suggestions. Thank you.
 

Dennis

Member
Joined
Oct 30, 2023
Posts
9
Likes
2
Hi @HalTrader, I am talking about a singleton class with only one instance that can be used with all Studies:
Java:
public final class DataContainer {

    private Map<Integer, Map<String, Object>> candleValues = new HashMap<>();

    private static DataContainer instance;

    private DataContainer() {}

    public static DataContainer getInstance() {
        if (instance == null) {
            instance = new DataContainer();
        }
        return instance;
    }

    // remaining code
}

You can then save something into that Container by calling "DataContainer.getInstance.THEMETHODYOUWANTTOCALL".
As the DataContainer is a singleton and therefore only exists once, each study is using the same java object.

Redis or MySQL is in my opinion just a different way of doing the same that I did with the DataContainer, but the Java Singleton is much (!) easier to do.
But, regardless which way you choose (Singleton, Database, ...) - we will always have the issue with the execution order of the studies. Saving the calculations is not the problem.

We have to figure out how MotiveWave decides the execution order - if we know this, we can share calculations from Study A to Study B without any problems.
 

Spin

Well-known member
Joined
May 22, 2019
Posts
477
Likes
191
Good thinking, @Dennis and @HalTrader ! :)

I too have fiddled with the same problem over and over. I even had 'timers' built in to Studies, so one would run on barOpen + 10 seconds, the next +30 seconds and so on. But those are just workarounds, and do not really tackle the root cause of this issue.

I will be monitoring this thread, and try to help out when I can. The singleton is a good idea, and perhaps JAVA's 'Thread' might help you guys along.
It allows to get the ID and Name of a thread. I would try those first to lift the fog and see what's going on. After that you could perhaps use 'yield' or 'sleep' or get/set the priority of a thread.

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Thread.html
 

Dennis

Member
Joined
Oct 30, 2023
Posts
9
Likes
2
Good thinking, @Dennis and @HalTrader ! :)

I too have fiddled with the same problem over and over. I even had 'timers' built in to Studies, so one would run on barOpen + 10 seconds, the next +30 seconds and so on. But those are just workarounds, and do not really tackle the root cause of this issue.

I will be monitoring this thread, and try to help out when I can. The singleton is a good idea, and perhaps JAVA's 'Thread' might help you guys along.
It allows to get the ID and Name of a thread. I would try those first to lift the fog and see what's going on. After that you could perhaps use 'yield' or 'sleep' or get/set the priority of a thread.

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Thread.html
Just tried printing the current ThreadID and ThreadName for each Study and also added debug messages for each pre-/post- and calculate-step.
They share the same Thread and are running in series. Study B starts when Study A finishes.
 

HalTrader

Active member
Joined
May 26, 2022
Posts
34
Likes
11
There is also another solution. See the link below:

In brief, "InputDescriptor" can be used to import an input series from the Cursor Data Window. Then, I think it should be possible to save them into different DataSeries in another study, and use them with "onBarOpen" or "onBarUpdate" to trigger a signal/condition that is dependent on values from both studies.

A few months ago, I imported Cursor Data Window values from one study to another study using this approach, but I never tried to create a condition that triggers alerts. It might be interesting to test it.
 

Dennis

Member
Joined
Oct 30, 2023
Posts
9
Likes
2
The InputDescriptor is not the right way for doing it the way that I imagine.

First of all, it doesn't list all of the other CursorData Values, just "Open,High,Low,Close,Midpoint,Typical Price,Weighted Price" - I assume this is due to the pricing plans of MotiveWave (I am using the free version).
Secondly, I would have to create a InputDescriptor for every value I want to consider - 10 values -> 10 InputDescriptors, 50 values -> 50 InputDescriptors.

I already have found a solution for that with my Singleton-Map-Approach and it is working great! - it's just that I currently can't control the execution order of my studies.

One simple example:
  1. Study A depends on calculations (CursorData Values) from Study B.
  2. MotiveWave decides, that Study A is executed first. Study B did not run yet and didn't calculate anything.
  3. Study A doesn't have any values from Study B and throws a NPE for simplicity.
  4. Study A is finished. Now MotiveWave is triggering Study B.
  5. Study B calculates everything and writes the values to CursorData and my DataContainer.
  6. If I now manually click on "update" in the SettingsWindow of Study A, Study A recalculates everything, it now has all of the calculations from Study B and can work with the values from Study B. No NPE anymore.
What do I want?
If I could control the execution order of my studies, I would first trigger Study B (and Study C, Study D, ...) and after all of my "calculate"-Studies are finished, I want to trigger Study A as the "brain"-Study as the last Study.
 

HalTrader

Active member
Joined
May 26, 2022
Posts
34
Likes
11
I have the Ultimate version and the InputDescriptor always shows OHLC, Midpoint, TP, WP values + custom DataSeries written by the user. But I totally agree on the fact that it is not user-friendly to create 10 values from 10 different InputDescriptors. There must be an easier way.
Otherwise, as @Spin suggested, another solution would be using Java's thread. I am not a programming or Java expert, but I wonder whether Java's thread can be used to control the execution order of your studies B, C, D, E and so on, then make sure that all the calculations from these studies are complete and study A is ready to process calculated DataSeries from other studies.

If someone finds a way to circumvent this problem, and posts a code example here, it would be great. I want to write a complex strategy in the future, where I combine DataSeries from multiple studies, then get all these values in a single strategy, similar to your study A, or the brain study. This strategy should receive all the DataSeries properly, process and open trades, and do trade management: send a limit order if conditions A, B, C are true. Then the limit order must be active as long as the conditions D and E are true, and cancel the limit order if the condition F is true, etc... I already found some code examples to write a simple Strategy, but managing the execution order of studies is a problem as you highlighted.
 

Spin

Well-known member
Joined
May 22, 2019
Posts
477
Likes
191
I have the Ultimate version and the InputDescriptor always shows OHLC, Midpoint, TP, WP values + custom DataSeries written by the user. But I totally agree on the fact that it is not user-friendly to create 10 values from 10 different InputDescriptors. There must be an easier way.
Otherwise, as @Spin suggested, another solution would be using Java's thread. I am not a programming or Java expert, but I wonder whether Java's thread can be used to control the execution order of your studies B, C, D, E and so on, then make sure that all the calculations from these studies are complete and study A is ready to process calculated DataSeries from other studies.

If someone finds a way to circumvent this problem, and posts a code example here, it would be great. I want to write a complex strategy in the future, where I combine DataSeries from multiple studies, then get all these values in a single strategy, similar to your study A, or the brain study. This strategy should receive all the DataSeries properly, process and open trades, and do trade management: send a limit order if conditions A, B, C are true. Then the limit order must be active as long as the conditions D and E are true, and cancel the limit order if the condition F is true, etc... I already found some code examples to write a simple Strategy, but managing the execution order of studies is a problem as you highlighted.
(I will say this quietly, to not stir up too much emotions 😄)

Perhaps create one biiiiiiiiiiiig package with in it a 'MASTER'-Study that calls the others in the correct order ?
 

Dennis

Member
Joined
Oct 30, 2023
Posts
9
Likes
2
(I will say this quietly, to not stir up too much emotions 😄)

Perhaps create one biiiiiiiiiiiig package with in it a 'MASTER'-Study that calls the others in the correct order ?
I already thought about something similar: creating static methods for the calculation in each study and then calling these in my desired order in my main study.. But I hoped that there is a better way 😅

Or not making them static and trying to creating new study instances with the DataContext from the main study.
 
Top