Do not understand examples.

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

Do not understand examples.

Post by Jan123 » Sun Jun 20, 2021 12:15 am

I am having trouble following the examples DataEditorBasicExample and MboVisualizerNoHistory. 

In both cases there seems to be no line that fills the newly created orderbooks with initial values, yet they are used as if they already contain the current orderbook.

Yes, I see the "onDepth" of the "Layer1ApiInjectorRelay" and the "send", "replace", "cancel" methods of the "MarketByOrderDepthDataListener". But shouldn't that just add one value after another once i run the module (= click the checkmark in "configure api plugins")

All the values are already there for the "Mbo visualizer: no history" immediately after i click the checkmark. shouldn't those values slowly build up when the levels of the orderbook change (and therefore invoke onDepth)? Where is the line that puts the initial values in the orderbook variables so that it can get correctly updated by onDepth?

I am talking about the variable "originalDataBooks" in the file "DataEditor"BasicExample.java"
and the variable "orderBook" in the file MboVisualizerNoHistory.java"


Here is the file DataEditor"BasicExample.java

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 editor1")
@Layer1ApiVersion(Layer1ApiVersionValue.VERSION2)
public class DataEditorBasicExample1 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<>(); // delclare the orderbooks
HashMap<String, OrderBook> modifiedDataBooks = new HashMap<>();
public DataEditorBasicExample1(Layer1ApiProvider provider) {
super(provider);
}
@Override
public void onInstrumentAdded(String alias, InstrumentInfo instrumentInfo) {
originalDataBooks.put(alias, new OrderBook()); // put a new entry in the orderbook for a new instrument
if (isActive) {
modifiedDataBooks.put(alias, new OrderBook());
}
super.onInstrumentAdded(alias, instrumentInfo);
}
@Override
public void onDepth(String alias, boolean isBid, int price, int size) { // a depth event will add data to the original orderbook
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); // and to the new orderbook
// 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() { // copy original orderbook one by one and change the numbers in the copy
// Currently bookmap shows normal data, let's replace it with modified.
for (String alias : originalDataBooks.keySet()) { // loop through the orderbooks fro each instrument
OrderBook originalBook = originalDataBooks.get(alias);
OrderBook modifiedBook = new OrderBook();
modifiedDataBooks.put(alias, modifiedBook);
for (Entry<Integer, Long> entry : originalBook.getBidMap().entrySet()) { // for some reason the original book is already filled. Where did that happen?
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() { // send the old orderbook back to bookmap
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) { // send all the modified entries to the orderbook of bookmap
// Erasing missing levels
for (Integer price : currentBook.getBidMap().keySet()) { // missing entries: send as 0
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()) { // valid entries, send one by one
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());
}
}
}

And here is the file MboVisualizerNoHistory.java

Code: Select all

 
package velox.api.layer1.simplified.demo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import velox.api.layer1.annotations.Layer1ApiVersion;
import velox.api.layer1.annotations.Layer1ApiVersionValue;
import velox.api.layer1.annotations.Layer1SimpleAttachable;
import velox.api.layer1.annotations.Layer1StrategyName;
import velox.api.layer1.data.InstrumentInfo;
import velox.api.layer1.layers.utils.OrderBook;
import velox.api.layer1.layers.utils.mbo.Order;
import velox.api.layer1.layers.utils.mbo.OrderBookMbo;
import velox.api.layer1.simplified.Api;
import velox.api.layer1.simplified.CustomModule;
import velox.api.layer1.simplified.CustomSettingsPanelProvider;
import velox.api.layer1.simplified.InitialState;
import velox.api.layer1.simplified.MarketByOrderDepthDataListener;
import velox.gui.StrategyPanel;
/**
* Visualizes MBO data
*/
@Layer1SimpleAttachable
@Layer1StrategyName("Mbo visualizer: no history")
@Layer1ApiVersion(Layer1ApiVersionValue.VERSION2)
public class MboVisualizerNoHistory
implements CustomModule, CustomSettingsPanelProvider, MarketByOrderDepthDataListener {
private OrderBookMbo orderBookMbo = new OrderBookMbo();
private OrderBook orderBook = new OrderBook();
private JLabel displayLabel;
private AtomicBoolean updateIsScheduled = new AtomicBoolean();
public MboVisualizerNoHistory() {
SwingUtilities.invokeLater(() -> {
displayLabel = new JLabel();
});
}
@Override
public void initialize(String alias, InstrumentInfo info, Api api, InitialState initialState) {
}
@Override
public void stop() {
}
@Override
public void send(String orderId, boolean isBid, int price, int size) {
orderBookMbo.send(orderId, isBid, price, size);
synchronized (orderBook) {
long levelSize = orderBook.getSizeFor(isBid, price, 0);
levelSize += size;
orderBook.onUpdate(isBid, price, levelSize);
}
scheduleUpdateIfNecessary();
}
@Override
public void replace(String orderId, int price, int size) {
Order oldOrder = orderBookMbo.getOrder(orderId);
boolean isBid = oldOrder.isBid();
int oldPrice = oldOrder.getPrice();
int oldSize = oldOrder.getSize();
orderBookMbo.replace(orderId, price, size);
synchronized (orderBook) {
long oldLevelSize = orderBook.getSizeFor(isBid, oldPrice, 0);
oldLevelSize -= oldSize;
orderBook.onUpdate(isBid, oldPrice, oldLevelSize);
long newLevelSize = orderBook.getSizeFor(isBid, price, 0);
newLevelSize += size;
orderBook.onUpdate(isBid, price, newLevelSize);
}
scheduleUpdateIfNecessary();
}
@Override
public void cancel(String orderId) {
Order oldOrder = orderBookMbo.getOrder(orderId);
boolean isBid = oldOrder.isBid();
int price = oldOrder.getPrice();
int size = oldOrder.getSize();
orderBookMbo.cancel(orderId);
synchronized (orderBook) {
long levelSize = orderBook.getSizeFor(isBid, price, 0);
levelSize -= size;
orderBook.onUpdate(isBid, price, levelSize);
}
scheduleUpdateIfNecessary();
}
private void scheduleUpdateIfNecessary() {
boolean shouldSchedule = !updateIsScheduled.getAndSet(true);
if (shouldSchedule) {
SwingUtilities.invokeLater(() -> {
updateIsScheduled.set(false);
StringBuilder builder = new StringBuilder();
builder.append("<html>");
synchronized (orderBook) {
Iterator<Entry<Integer, Long>> askItterator = orderBook.getAskMap().entrySet().iterator();
Iterator<Entry<Integer, Long>> bidItterator = orderBook.getBidMap().entrySet().iterator();
List<String> askRows = new ArrayList<>();
for (int i = 0; i < 10 && askItterator.hasNext(); ++i) {
Entry<Integer, Long> nextAskEntry = askItterator.next();
askRows.add("ASK Distance: " + i + " Price(int): " + nextAskEntry.getKey() + " Size: "
+ nextAskEntry.getValue() + "<br/>");
}
Collections.reverse(askRows);
askRows.forEach(builder::append);
for (int i = 0; i < 10 && bidItterator.hasNext(); ++i) {
Entry<Integer, Long> nextBidEntry = bidItterator.next();
builder.append("BID Distance: " + i + " Price(int): " + nextBidEntry.getKey() + " Size: "
+ nextBidEntry.getValue() + "<br/>");
}
}
builder.append("</html>");
displayLabel.setText(builder.toString());
});
}
}
@Override
public StrategyPanel[] getCustomSettingsPanels() {
displayLabel = new JLabel();
scheduleUpdateIfNecessary();
StrategyPanel ordersPanel = new StrategyPanel("Order book");
ordersPanel.add(displayLabel);
return new StrategyPanel[] { ordersPanel };
}
}


 

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

Re: Do not understand examples.

Post by Andry API support » Mon Jun 21, 2021 10:46 am

Hi,
orderbooks are initially formed with a series of depth updates happening immediately after the addon is run. So methods that initially fill and then update the orderbook are the same.

Jan123
Posts: 18
Joined: Tue Apr 20, 2021 2:28 pm
Has thanked: 19 times
Been thanked: 3 times

Re: Do not understand examples.

Post by Jan123 » Mon Jun 21, 2021 11:43 am

Hi AndreyR,

Thanks for this information. So the orderBookMbo variable is filled by the "send" method or the "onMboSend" method with all the orders that are currently sitting in the orderbook, and the regular orderBook variable is filled via the "onDepth" method?

 

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

Re: Do not understand examples.

Post by Andry API support » Mon Jun 21, 2021 1:13 pm

Yes

Post Reply