variable sliders in @Layer1UpstreamDataEditor ?

Custom indicators, trading strategies, data export and recording and more...
Jan123
Posts: 18
Joined: Tue Apr 20, 2021 2:28 pm
Has thanked: 19 times
Been thanked: 3 times

variable sliders in @Layer1UpstreamDataEditor ?

Post by Jan123 » Mon Jun 21, 2021 6:09 am

I am trying to make a program that changes the displayed heatmap by changing the orderbook (filter out large orders from the MBO orderbook).

Below is the "DataEditorBasicExample.java" from your github. 

How can i add sliders to this? For example the file has two parameters: PRICE_OFFSET and SIZE_MULTIPLIER. How can I make sliders in the GUI dialog box for those parameters?

I tried to add sliders according to other examples from your github that had sliders, but it would always crash and give "IllegalStateException". Is there an issue with mixing @Layer1UpstreamDataEditor and @Layer1SimpleAttachable? If so, how can i get sliders then?

I want to filter out large orders from the MBO limit orderbook. The code works conceptually, but i would like to add a slider to adjust the order size to be filtered. 

 

Code: Select all

 
package velox.api.layer1.simpledemo.dataeditor;
import java.util.HashMap;
import java.util.Map.Entry;
import velox.api.layer1.Layer1ApiFinishable;
import velox.api.layer1.Layer1ApiProvider;
import velox.api.layer1.annotations.Layer1ApiVersion;
import velox.api.layer1.annotations.Layer1ApiVersionValue;
import velox.api.layer1.annotations.Layer1StrategyName;
import velox.api.layer1.annotations.Layer1UpstreamDataEditor;
import velox.api.layer1.data.InstrumentInfo;
import velox.api.layer1.data.TradeInfo;
import velox.api.layer1.layers.Layer1ApiInjectorRelay;
import velox.api.layer1.layers.utils.OrderBook;
import velox.api.layer1.messages.UserMessageLayersChainCreatedTargeted;
/** Offsets depth data and trades 3 levels up and doubles displayed sizes.*/
@Layer1UpstreamDataEditor
@Layer1StrategyName("Data editor")
@Layer1ApiVersion(Layer1ApiVersionValue.VERSION2)
public class DataEditorBasicExample extends Layer1ApiInjectorRelay implements Layer1ApiFinishable {
/** Sizes of depth updates and trades will be multiplied by this */
private static final int SIZE_MULTIPLIER = 2;
/** How many levels to offset the price */
private static final int PRICE_OFFSET = 3;
private boolean isActive = false;
HashMap<String, OrderBook> originalDataBooks = new HashMap<>();
HashMap<String, OrderBook> modifiedDataBooks = new HashMap<>();
public DataEditorBasicExample(Layer1ApiProvider provider) {
super(provider);
}
@Override
public void onInstrumentAdded(String alias, InstrumentInfo instrumentInfo) {
originalDataBooks.put(alias, new OrderBook());
if (isActive) {
modifiedDataBooks.put(alias, new OrderBook());
}
super.onInstrumentAdded(alias, instrumentInfo);
}
@Override
public void onDepth(String alias, boolean isBid, int price, int size) {
originalDataBooks.get(alias).onUpdate(isBid, price, size);
// If active - modify data. Otherwise we just get data for initialization
if (isActive) {
price = modifyPrice(price);
size = modifySize(size);
modifiedDataBooks.get(alias).onUpdate(isBid, price, size);
// This could be outside if, but there is no difference since
// inactive strategy has nowhere to forward data
super.onDepth(alias, isBid, price, size);
}
}
@Override
public void onTrade(String alias, double price, int size, TradeInfo tradeInfo) {
super.onTrade(alias, price + PRICE_OFFSET, size * SIZE_MULTIPLIER, tradeInfo);
}
private int modifySize(long size) {
size *= SIZE_MULTIPLIER;
return (int)size;
}
private int modifyPrice(int price) {
price += PRICE_OFFSET;
return price;
}
@Override
public void finish() {
injectSynchronously(() -> {
if (isActive) {
isActive = false;
deactivate();
}
});
}
@Override
public void onUserMessage(Object data) {
if (data instanceof UserMessageLayersChainCreatedTargeted) {
UserMessageLayersChainCreatedTargeted message = (UserMessageLayersChainCreatedTargeted) data;
if (message.targetClass == getClass()) {
isActive = true;
activate();
}
}
super.onUserMessage(data);
}
private void activate() {
// Currently bookmap shows normal data, let's replace it with modified.
for (String alias : originalDataBooks.keySet()) {
OrderBook originalBook = originalDataBooks.get(alias);
OrderBook modifiedBook = new OrderBook();
modifiedDataBooks.put(alias, modifiedBook);
for (Entry<Integer, Long> entry : originalBook.getBidMap().entrySet()) {
modifiedBook.onUpdate(true,
modifyPrice(entry.getKey()),
modifySize(entry.getValue()));
}
for (Entry<Integer, Long> entry : originalBook.getAskMap().entrySet()) {
modifiedBook.onUpdate(false,
modifyPrice(entry.getKey()),
modifySize(entry.getValue()));
}
sendUpdates(alias, originalBook, modifiedBook);
}
}
private void deactivate() {
for (String alias : originalDataBooks.keySet()) {
OrderBook originalBook = originalDataBooks.get(alias);
OrderBook modifiedBook = modifiedDataBooks.remove(alias);
sendUpdates(alias, modifiedBook, originalBook);
}
}
private void sendUpdates(String alias, OrderBook currentBook, OrderBook intendedBook) {
// Erasing missing levels
for (Integer price : currentBook.getBidMap().keySet()) {
if (!intendedBook.getBidMap().containsKey(price)) {
super.onDepth(alias, true, price, 0);
}
}
for (Integer price : currentBook.getAskMap().keySet()) {
if (!intendedBook.getAskMap().containsKey(price)) {
super.onDepth(alias, false, price, 0);
}
}
for (Entry<Integer, Long> entry : intendedBook.getBidMap().entrySet()) {
super.onDepth(alias, true, entry.getKey(), entry.getValue().intValue());
}
for (Entry<Integer, Long> entry : intendedBook.getAskMap().entrySet()) {
super.onDepth(alias, false, entry.getKey(), entry.getValue().intValue());
}
}
}

Andry API support
Posts: 548
Joined: Mon Jul 09, 2018 11:18 am
Has thanked: 25 times
Been thanked: 85 times

Re: variable sliders in @Layer1UpstreamDataEditor ?

Post by Andry API support » Mon Jun 21, 2021 12:32 pm

1) If the task is just to add a GUI element your module should implement Layer1CustomPanelsGetter. Its method getCustomGuiFor returns an array of panels your GUI elements are placed on. Here is an implementation example. Changing the slider value results just in a log message.

Code: Select all

    int currentSliderValue;
   
    // ........

    @Override
    public StrategyPanel[] getCustomGuiFor(String alias, String indicatorName) {
        JSlider slider = new JSlider(0, 100, currentSliderValue);
        JLabel statusLabel = new JLabel("", JLabel.LEFT);
        statusLabel.setText(String.valueOf(currentSliderValue));
        slider.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                if (slider.getValueIsAdjusting()) {//adjusting
                    int value = (int) ((JSlider) e.getSource()).getValue();
                    statusLabel.setText(String.valueOf(value));
                } else {//adjusted
                    currentSliderValue = (int) ((JSlider) e.getSource()).getValue();
                    Log.info("Now slider value is " + currentSliderValue);
                }
            }
        });

        StrategyPanel panel = new StrategyPanel("Settings");
        panel.setLayout(new GridBagLayout());
        
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.gridx = 0;
        constraints.weightx = 0.5;
        panel.add(new JLabel("slider"), constraints);
        constraints.gridx = 1;
        constraints.weightx = 0.5; 
        panel.add(slider, constraints);
        
        return new StrategyPanel[] { panel };
    }

2)
it would always crash and give "IllegalStateException". Is there an issue with mixing @Layer1UpstreamDataEditor and @Layer1SimpleAttachable?
Yes, mixing Layer1SimpleAttachable and Layer1UpstreamDataEditor is not allowed. They are 2 different methods (more info here https://bookmap.com/knowledgebase/docs/ ... Indicators).

3) Please note: if you need to change the orderbook state in Bookmap you will need to report changes. Assume you need to remove orders sized above 1000 from the Bookmap orderbook. You will need to report removing them. Assume you need to bring them back. You will need to report adding them. So an original (unfiltered) orderbook must be stored in your module and if the filtering parameters change the difference between unfiltered and filtered orderbook must be reported to Bookmap.

Post Reply