package notesserver; import java.awt.Color; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; 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.simplified.Api; import velox.api.layer1.simplified.BboListener; import velox.api.layer1.simplified.CustomModule; import velox.api.layer1.simplified.InitialState; @Layer1SimpleAttachable @Layer1StrategyName("BboReporter") @Layer1ApiVersion(Layer1ApiVersionValue.VERSION2) public class BboReporter implements CustomModule, BboListener { private static final String header = "\"Symbol\",\"Price Level\",\"Note\",\"Foreground Color\",\"Background Color\"," + "\"Text Alignment\",\"Notification Enabled\",\"Sound Notification Enabled\",\"Notification Is Repeatable\"," + "\"Delay Before Repeating\",\"Subscribing Offset\",\"Notification Sound\"\r\n"; private static final int port = 8089; private static final String newLine="\r\n"; private String alias; private double pips; private AtomicBoolean enabled = new AtomicBoolean(true); private ServerSocket serverSocket; private final ExecutorService readNotesExecutor = Executors.newSingleThreadExecutor(); private final ExecutorService incomingBboExecutor = Executors.newSingleThreadExecutor(); private NoteUnit actualBbo; private NoteUnit reportedBbo; private final Object unitLock = new Object(); @Override public void initialize(String alias, InstrumentInfo info, Api api, InitialState initialState) { this.alias = alias; this.pips = info.pips; start(); } @Override public void stop() { incomingBboExecutor.shutdownNow(); enabled.set(false); try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } readNotesExecutor.shutdownNow(); } @Override public void onBbo(int bidPrice, int bidSize, int askPrice, int askSize) { if (bidPrice == 0) return; Runnable runnable = () -> { NoteUnit unit = new NoteUnit(); unit.setSymbol(alias); unit.setPriceLevel((double)(bidPrice * pips)); unit.setForegroundColor(Color.decode("#ffffff")); unit.setBackgroundColor(Color.decode("#cc3300")); unit.setNote("Bbo is " + String.valueOf(unit.getPriceLevel())); synchronized (unitLock) { actualBbo = unit; } }; incomingBboExecutor.execute(runnable); } private void start() { Thread server = new Thread(() -> { try (ServerSocket socket = new ServerSocket(port)) { serverSocket = socket; while (enabled.get()) { Socket connection = socket.accept(); try { BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); // read first line of request String request = in.readLine(); if (request == null) { continue; } Runnable runnable = () -> { try { OutputStream out = new BufferedOutputStream(connection.getOutputStream()); if (request.startsWith("GET")) { StringBuilder sb = new StringBuilder(); sb.append(header); synchronized (unitLock) { if (reportedBbo != null) { NoteUnit unitToRemove = new NoteUnit(); unitToRemove.setSymbol(alias); unitToRemove.setPriceLevel(reportedBbo.getPriceLevel()); sb.append(unitToRemove.getCsvLine()); } if (actualBbo != null) { sb.append(actualBbo.getCsvLine()); reportedBbo = actualBbo; } } String response = sb.toString(); PrintStream printStream = new PrintStream(out); printStream.print("HTTP/1.0 200 OK" + newLine + "Content-Type: text/plain" + newLine + "Date: " + new Date() + newLine + "Content-length: " + response.length() + newLine + newLine + response); printStream.close(); } } catch (IOException e) { e.printStackTrace(); } }; readNotesExecutor.execute(runnable); } catch (Exception e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } }); server.start(); } }