Skip to content

Commit 06e01aa

Browse files
Merge branch 'bookmap-api-v1'
# Conflicts: # bitmex-adapter/src/com/bookmap/plugins/layer0/bitmex/Provider.java # bitmex-adapter/src/com/bookmap/plugins/layer0/bitmex/adapter/BmConnector.java # bitmex-adapter/src/com/bookmap/plugins/layer0/bitmex/adapter/JsonParser.java
2 parents 5fc7ed7 + 6ede234 commit 06e01aa

3 files changed

Lines changed: 100 additions & 58 deletions

File tree

bitmex-adapter/src/com/bookmap/plugins/layer0/bitmex/Provider.java

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.util.List;
99
import java.util.Map;
1010
import java.util.Set;
11+
import java.util.concurrent.CopyOnWriteArrayList;
1112

1213
import com.bookmap.plugins.layer0.bitmex.adapter.BmConnector;
1314
import com.bookmap.plugins.layer0.bitmex.adapter.BmInstrument;
@@ -30,8 +31,11 @@
3031
import velox.api.layer0.live.ExternalLiveBaseProvider;
3132
import velox.api.layer1.Layer1ApiAdminListener;
3233
import velox.api.layer1.Layer1ApiDataListener;
34+
import velox.api.layer1.annotations.Layer1ApiVersion;
35+
import velox.api.layer1.annotations.Layer1ApiVersionValue;
3336
import velox.api.layer1.common.Log;
3437
import velox.api.layer1.data.BalanceInfo;
38+
import velox.api.layer1.data.BmSimpleHistoricalDataInfo;
3539
import velox.api.layer1.data.DisconnectionReason;
3640
import velox.api.layer1.data.ExecutionInfo;
3741
import velox.api.layer1.data.InstrumentInfo;
@@ -51,12 +55,14 @@
5155
import velox.api.layer1.data.OrderUpdateParameters;
5256
import velox.api.layer1.data.SimpleOrderSendParameters;
5357
import velox.api.layer1.data.StatusInfo;
58+
import velox.api.layer1.data.SubscribeInfo;
5459
import velox.api.layer1.data.SystemTextMessageType;
5560
import velox.api.layer1.data.TradeInfo;
5661
import velox.api.layer1.data.UserPasswordDemoLoginData;
5762
import velox.api.layer1.layers.utils.OrderBook;
5863

59-
@Layer0LiveModule
64+
@Layer1ApiVersion(Layer1ApiVersionValue.VERSION1)
65+
@Layer0LiveModule(shortName = "MEX", fullName = "BitMEX")
6066
public class Provider extends ExternalLiveBaseProvider {
6167

6268
private BmConnector connector;
@@ -82,6 +88,8 @@ public class Provider extends ExternalLiveBaseProvider {
8288
private List<String> batchCancels = new LinkedList<>();
8389
private Map<String, BalanceInfo.BalanceInCurrency> balanceMap = new HashMap<>();
8490

91+
private CopyOnWriteArrayList<SubscribeInfo> knownInstruments = new CopyOnWriteArrayList<>();
92+
8593
protected class Instrument {
8694
protected final String alias;
8795
protected final double pips;
@@ -110,6 +118,14 @@ public BmConnector getConnector() {
110118
return connector;
111119
}
112120

121+
public List<SubscribeInfo> getKnownInstruments() {
122+
return knownInstruments;
123+
}
124+
125+
public void setKnownInstruments(CopyOnWriteArrayList<SubscribeInfo> knownInstruments) {
126+
this.knownInstruments = knownInstruments;
127+
}
128+
113129
/**
114130
* <p>
115131
* Generates alias from symbol, exchange and type of the instrument. Alias
@@ -135,7 +151,11 @@ public static String testReponseForError(String str) {
135151
}
136152

137153
@Override
138-
public void subscribe(String symbol, String exchange, String type) {
154+
public void subscribe(SubscribeInfo subscribeInfo) {
155+
final String symbol = subscribeInfo.symbol;
156+
final String exchange = subscribeInfo.exchange;
157+
final String type = subscribeInfo.type;
158+
139159
Log.info("[bitmex] Provider subscribe");
140160
String alias = createAlias(symbol, exchange, type);
141161
// Since instruments also will be accessed from the data generation
@@ -270,7 +290,7 @@ private SimpleOrderSendParameters createStopLossFromParameters(SimpleOrderSendPa
270290
int offsetMultiplier = simpleParams.isBuy ? 1 : -1;
271291

272292
double limitPriceChecked = checkLImitPriceForBracket(simpleParams, bmInstrument);
273-
293+
274294
SimpleOrderSendParameters stopLoss = new SimpleOrderSendParameters(
275295
simpleParams.alias,
276296
!simpleParams.isBuy, // !
@@ -299,13 +319,12 @@ private SimpleOrderSendParameters createTakeProfitFromParameters(SimpleOrderSend
299319
simpleParams.sizeMultiplier);
300320
return takeProfit;
301321
}
302-
303-
private double checkLImitPriceForBracket(SimpleOrderSendParameters simpleParams, BmInstrument bmInstrument){
322+
323+
private double checkLImitPriceForBracket(SimpleOrderSendParameters simpleParams, BmInstrument bmInstrument) {
304324
double limitPriceChecked = simpleParams.limitPrice;
305325
if (Double.isNaN(simpleParams.limitPrice)) {
306326
OrderBook orderBook = bmInstrument.getOrderBook();
307-
limitPriceChecked = simpleParams.isBuy ?
308-
orderBook.getBestAskPriceOrNone() * bmInstrument.getTickSize()
327+
limitPriceChecked = simpleParams.isBuy ? orderBook.getBestAskPriceOrNone() * bmInstrument.getTickSize()
309328
: orderBook.getBestBidPriceOrNone() * bmInstrument.getTickSize();
310329
}
311330
return limitPriceChecked;
@@ -906,23 +925,22 @@ public void listenForMargin(UnitMargin margin) {
906925
long tempMultiplier = 100000000;// temp
907926
String currency = margin.getCurrency();
908927
BalanceInfo.BalanceInCurrency currentBic = balanceMap.get(margin.getCurrency());
909-
BalanceInfo.BalanceInCurrency newBic;
910928
if (currentBic == null) {// no current balance balance
911-
newBic = new BalanceInfo.BalanceInCurrency(0.0, 0.0, 0.0, 0.0, 0.0, margin.getCurrency(), null);
912-
} else {
913-
newBic = new BalanceInfo.BalanceInCurrency(currentBic.balance,
914-
margin.getRealisedPnl() == null ? currentBic.realizedPnl
915-
: (double) margin.getRealisedPnl() / tempMultiplier,
916-
margin.getUnrealisedPnl() == null ? currentBic.unrealizedPnl
917-
: (double) margin.getUnrealisedPnl() / tempMultiplier,
918-
currentBic.previousDayBalance, margin.getAvailableMargin() == null ? currentBic.netLiquidityValue
919-
: (double) margin.getAvailableMargin() / tempMultiplier,
920-
currency,
921-
currentBic.rateToBase);
929+
currentBic = new BalanceInfo.BalanceInCurrency(0.0, 0.0, 0.0, 0.0, 0.0, currency, null);
922930
}
931+
currentBic = new BalanceInfo.BalanceInCurrency(
932+
currentBic.balance,
933+
margin.getRealisedPnl() == null ? currentBic.realizedPnl
934+
: (double) margin.getRealisedPnl() / tempMultiplier,
935+
margin.getUnrealisedPnl() == null ? currentBic.unrealizedPnl
936+
: (double) margin.getUnrealisedPnl() / tempMultiplier,
937+
currentBic.previousDayBalance,
938+
margin.getAvailableMargin() == null ? currentBic.netLiquidityValue
939+
: (double) margin.getAvailableMargin() / tempMultiplier,
940+
currency,
941+
currentBic.rateToBase);
923942

924-
balanceMap.remove(currency);
925-
balanceMap.put(currency, newBic);
943+
balanceMap.put(currency, currentBic);
926944
BalanceInfo info = new BalanceInfo(new ArrayList<BalanceInfo.BalanceInCurrency>(balanceMap.values()));
927945
tradingListeners.forEach(l -> l.onBalance(info));
928946
}
@@ -1073,24 +1091,27 @@ private void checkIfLinkedAndAddToMaps(UnitOrder order) {
10731091
@Override
10741092
public Layer1ApiProviderSupportedFeatures getSupportedFeatures() {
10751093
// Expanding parent supported features, reporting basic trading support
1076-
Layer1ApiProviderSupportedFeaturesBuilder a;
1094+
Layer1ApiProviderSupportedFeaturesBuilder a = super.getSupportedFeatures().toBuilder();
10771095

1078-
if (isCredentialsEmpty) {
1079-
return super.getSupportedFeatures().toBuilder().build();
1096+
if (!isCredentialsEmpty) {
1097+
a.setTrading(true);
10801098
}
10811099

1082-
a = super.getSupportedFeatures().toBuilder().setTrading(true)
1083-
.setOco(true)
1100+
a.setOco(true)
10841101
.setBrackets(true)
10851102
.setSupportedOrderDurations(Arrays.asList(new OrderDuration[] { OrderDuration.GTC }))
10861103
// At the moment of writing this method it was not possible to
10871104
// report limit orders support, but no stop orders support
10881105
// If you actually need it, you can report stop orders support
10891106
// but reject stop orders when those are sent.
1090-
.setSupportedStopOrders(Arrays.asList(new OrderType[] { OrderType.LMT, OrderType.MKT }));
1091-
1092-
a.setBalanceSupported(true);
1093-
a.setTrailingStopsAsIndependentOrders(true);
1107+
.setSupportedStopOrders(Arrays.asList(new OrderType[] { OrderType.LMT, OrderType.MKT }))
1108+
.setBalanceSupported(true)
1109+
.setTrailingStopsAsIndependentOrders(true)
1110+
.setExchangeUsedForSubscription(false)
1111+
.setTypeUsedForSubscription(false)
1112+
.setHistoricalDataInfo(new BmSimpleHistoricalDataInfo(
1113+
"http://bitmex.historicaldata.bookmap.com:38080/historical-data-server-1.0/"))
1114+
.setKnownInstruments(knownInstruments);
10941115

10951116
// Log.info("PROVIDER getSupportedFeatures INVOKED");
10961117
return a.build();

bitmex-adapter/src/com/bookmap/plugins/layer0/bitmex/adapter/BmConnector.java

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.nio.channels.UnresolvedAddressException;
1212
import java.time.ZoneOffset;
1313
import java.time.ZonedDateTime;
14+
import java.util.ArrayList;
1415
import java.util.Collections;
1516
import java.util.HashMap;
1617
import java.util.HashSet;
@@ -19,6 +20,7 @@
1920
import java.util.Set;
2021
import java.util.Timer;
2122
import java.util.TimerTask;
23+
import java.util.concurrent.CopyOnWriteArrayList;
2224
import java.util.concurrent.CountDownLatch;
2325
import java.util.concurrent.Executors;
2426
import java.util.concurrent.ScheduledExecutorService;
@@ -37,6 +39,7 @@
3739
import com.bookmap.plugins.layer0.bitmex.adapter.ConnectorUtils.WebSocketOperation;
3840

3941
import velox.api.layer1.common.Log;
42+
import velox.api.layer1.data.SubscribeInfo;
4043

4144
public class BmConnector implements Runnable {
4245

@@ -53,7 +56,7 @@ public class BmConnector implements Runnable {
5356
private boolean isReconnecting = false;
5457
private Provider provider;
5558
private TradeConnector tradeConnector;
56-
59+
5760
private ScheduledExecutorService executionsResetTimer;
5861
private int executionDay = 0;
5962
private boolean isExecutionReset;
@@ -164,7 +167,7 @@ public void wsConnect() {
164167
(Object[]) ConnectorUtils.getAuthenticatedTopicsList());
165168
String res = JsonParser.gson.toJson(wsData);
166169
socket.sendMessage(res);
167-
170+
168171
reportHistoricalExecutions("Filled");
169172
reportHistoricalExecutions("Canceled");
170173
}
@@ -278,7 +281,7 @@ public HashMap<String, BmInstrument> getActiveInstrumentsMap() {
278281

279282
private void launchSnapshotTimer(BmInstrument instr) {
280283
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
281-
284+
282285
TimerTask task = new TimerTask() {
283286
@Override
284287
public void run() {
@@ -296,15 +299,16 @@ public void run() {
296299
Log.info("[bitmex] BmConnector launchSnapshotTimer(): " + now);
297300
timer.schedule(task, 10000);
298301
}
299-
302+
300303
private void launchExecutionsResetTimer() {
301304
class CustomThreadFactory implements ThreadFactory {
302305
public Thread newThread(Runnable r) {
303306
return new Thread(r, "-> BmConnector: executionsResetTimer");
304307
}
305308
}
306309

307-
ScheduledExecutorService executionsResetTimer = Executors.newSingleThreadScheduledExecutor(new CustomThreadFactory());
310+
ScheduledExecutorService executionsResetTimer = Executors
311+
.newSingleThreadScheduledExecutor(new CustomThreadFactory());
308312
this.executionsResetTimer = executionsResetTimer;
309313
Log.info("[bitmex] BmConnector launchExecutionsResetTimer(): ");
310314
executionsResetTimer.scheduleWithFixedDelay(new Runnable() {
@@ -314,16 +318,15 @@ public void run() {
314318

315319
if (executionDay < dayNow && !isExecutionReset) {
316320
executionDay = dayNow;
317-
321+
318322
Set<BmInstrument> instruments = new HashSet<>();
319323
synchronized (activeBmInstrumentsMap) {
320-
instruments.addAll(activeBmInstrumentsMap.values());
324+
instruments.addAll(activeBmInstrumentsMap.values());
321325
}
322-
for (BmInstrument instrument : instruments){
326+
for (BmInstrument instrument : instruments) {
323327
instrument.setExecutionsVolume(0);
324328
}
325-
326-
329+
327330
isExecutionReset = true;
328331
} else if (executionDay == dayNow) {
329332
isExecutionReset = false;
@@ -347,7 +350,7 @@ public void unSubscribe(BmInstrument instr) {
347350
sendWebsocketMessage(instr.getUnSubscribeReq());
348351

349352
Timer timer = instr.getSnapshotTimer();
350-
if(timer != null){
353+
if (timer != null) {
351354
timer.cancel();
352355
Log.info("[bitmex] BmConnector unSubscribe: timer gets cancelled");
353356
}
@@ -359,15 +362,15 @@ private int countExecutionsVolume(String symbol) {
359362
String dataADayBefore = ConnectorUtils.getDateTwentyFourHoursAgoAsUrlEncodedString();
360363
StringBuilder sb = new StringBuilder();
361364
sb.append("/api/v1/execution?symbol=").append(symbol)
362-
.append("&filter=%7B%22ordStatus%22%3A%22Filled%22%7D&count=100&reverse=false&startTime=")
363-
.append(dataADayBefore);
365+
.append("&filter=%7B%22ordStatus%22%3A%22Filled%22%7D&count=100&reverse=false&startTime=")
366+
.append(dataADayBefore);
364367

365368
String addr = sb.toString();
366369

367370
String st0 = tradeConnector.makeRestGetQuery(addr);
368371
UnitOrder[] orders = JsonParser.getArrayFromJson(st0, UnitOrder[].class);
369372
int sum = 0;
370-
373+
371374
if (orders != null && orders.length > 0) {
372375
for (UnitOrder order : orders) {
373376
sum += order.getOrderQty();
@@ -377,30 +380,31 @@ private int countExecutionsVolume(String symbol) {
377380
Log.info("[bitmex] BmConnector countExecution volume: " + st0);
378381
return sum;
379382
}
380-
383+
381384
private void reportHistoricalExecutions(String ordStatus) {
382-
// private void reportHistoricalExecutions(String symbol, String ordStatus) {
385+
// private void reportHistoricalExecutions(String symbol, String
386+
// ordStatus) {
383387
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
384388
ZonedDateTime startTime = now.minusDays(0)
385389
.minusHours(now.getHour())
386390
.minusMinutes(now.getMinute())
387391
.minusSeconds(now.getSecond())
388392
.minusNanos(now.getNano());
389-
393+
390394
List<UnitExecution> historicalExecutions = new LinkedList<>();
391395
for (int i = 0;; i += 500) {
392396
StringBuilder sb = new StringBuilder();
393397
sb.append("/api/v1/execution?").append("filter=%7B%22ordStatus%22%3A%20%22")
394-
.append(ordStatus).append("%22%7D&count=500&reverse=true&startTime=")
395-
.append(startTime).append("&endTime=").append(now)
396-
.append("&start=").append(i);
397-
398+
.append(ordStatus).append("%22%7D&count=500&reverse=true&startTime=")
399+
.append(startTime).append("&endTime=").append(now)
400+
.append("&start=").append(i);
401+
398402
String addr = sb.toString();
399403
String response = tradeConnector.makeRestGetQuery(addr);
400-
404+
401405
UnitExecution[] executions = JsonParser.getArrayFromJson(response,
402406
UnitExecution[].class);
403-
407+
404408
if (executions == null || executions.length == 0) {
405409
break;
406410
} else {
@@ -412,9 +416,10 @@ private void reportHistoricalExecutions(String ordStatus) {
412416
}
413417
}
414418
Log.info("[bitmex] BmConnector report " + ordStatus + ": listSize = " + historicalExecutions.size());
415-
419+
416420
if (historicalExecutions != null && historicalExecutions.size() > 0) {
417-
provider.updateExecutionsHistory(historicalExecutions.toArray(new UnitExecution[historicalExecutions.size()]));
421+
provider.updateExecutionsHistory(
422+
historicalExecutions.toArray(new UnitExecution[historicalExecutions.size()]));
418423
}
419424
}
420425

@@ -434,9 +439,17 @@ public void run() {
434439

435440
if (activeBmInstrumentsMap.isEmpty()) {
436441
fillActiveBmInstrumentsMap();
442+
443+
CopyOnWriteArrayList<SubscribeInfo> knownInstruments = new CopyOnWriteArrayList<>();
444+
for (BmInstrument instrument : activeBmInstrumentsMap.values()) {
445+
knownInstruments.add(new SubscribeInfo(instrument.getSymbol(), null, null));
446+
}
447+
provider.setKnownInstruments(knownInstruments);
448+
437449
launchExecutionsResetTimer();
438-
if (activeBmInstrumentsMap.isEmpty())
450+
if (activeBmInstrumentsMap.isEmpty()) {
439451
continue;
452+
}
440453
}
441454
if (!interruptionNeeded) {
442455
wsConnect();

0 commit comments

Comments
 (0)