25: Add dynamic Jupiter Perps liquidation price variables to alarm config

This commit is contained in:
2026-08-05 10:12:38 +02:00
parent 228698e3e4
commit 776f626abb
2 changed files with 154 additions and 25 deletions
@@ -57,6 +57,8 @@ public final class JupiterPerpsAlarmImpl {
entryPriceVariableRefresher.refresh();
System.out.println("Fetching done.");
entryPriceVariableRefresher.startPeriodicRefresh();
JupiterPerpsEntryPriceVariableRefreshWatcher entryPriceVariableRefreshWatcher =
new JupiterPerpsEntryPriceVariableRefreshWatcher(
config.alarmConfiguration().getParent(),
@@ -106,7 +108,10 @@ public final class JupiterPerpsAlarmImpl {
}
Runtime.getRuntime().addShutdownHook(new Thread(
() -> clients.forEach(OracleWebSocketClient::close),
() -> {
entryPriceVariableRefresher.close();
clients.forEach(OracleWebSocketClient::close);
},
"shutdown"
));
@@ -2,13 +2,17 @@ package com.r35157.jupiterperpsalarm.impl.ref;
import com.r35157.libs.jupiter.perps.JupiterPerpsPosition;
import com.r35157.libs.jupiter.perps.JupiterPerpsService;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public final class JupiterPerpsEntryPriceVariableRefresher {
public final class JupiterPerpsEntryPriceVariableRefresher
implements AutoCloseable {
public JupiterPerpsEntryPriceVariableRefresher(
Map<String, String> variables,
@@ -16,13 +20,46 @@ public final class JupiterPerpsEntryPriceVariableRefresher {
) {
this.variables = Objects.requireNonNull(variables, "variables");
this.jupiterPerpsService = Objects.requireNonNull(jupiterPerpsService, "jupiterPerpsService");
scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> {
Thread thread = new Thread(
runnable,
"jupiter-perps-price-variable-refresher"
);
thread.setDaemon(true);
return thread;
});
}
public void refresh() {
public void startPeriodicRefresh() {
scheduler.scheduleWithFixedDelay(
this::refreshPeriodically,
REFRESH_INTERVAL_SECONDS,
REFRESH_INTERVAL_SECONDS,
TimeUnit.SECONDS
);
System.out.println(
"Periodic Jupiter Perps price variable refresh started with interval: "
+ REFRESH_INTERVAL_SECONDS
+ " seconds"
);
}
@Override
public void close() {
scheduler.shutdownNow();
}
public synchronized void refresh() {
System.out.println("Executing refresh now...");
ΩSolanaWalletIdΩ wallet = variables.get("JUPITER_PERPS_WALLET");
if (wallet == null || wallet.isBlank()) {
System.err.println("Cannot refresh Jupiter Perps entry price variables: JUPITER_PERPS_WALLET is not configured");
System.err.println("Cannot refresh Jupiter Perps price variables: JUPITER_PERPS_WALLET is not configured");
return;
}
@@ -35,41 +72,92 @@ public final class JupiterPerpsEntryPriceVariableRefresher {
+ " open Jupiter Perps positions for wallet: " + wallet
);
removeEntryPriceVariables();
Map<String, String> previousPriceVariables = copyPriceVariables();
removePriceVariables();
for (JupiterPerpsPosition position : positions) {
String variableName = createEntryPriceVariableName(position);
String entryPriceVariableName = createEntryPriceVariableName(position);
System.out.println(
"Jupiter Perps position maps to variable "
+ variableName
+ " = "
+ position.entryPrice()
putPriceVariable(
previousPriceVariables,
entryPriceVariableName,
position.entryPrice().toPlainString()
);
variables.put(variableName, position.entryPrice().toPlainString());
String liquidationPriceVariableName = createLiquidationPriceVariableName(position);
putPriceVariable(
previousPriceVariables,
liquidationPriceVariableName,
position.liquidationPrice().toPlainString()
);
}
} catch (IOException | InterruptedException exception) {
} catch (IOException |
InterruptedException exception) {
if (exception instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
System.err.println(
"Could not refresh Jupiter Perps entry price variables: "
+ exception.getMessage()
"Could not refresh Jupiter Perps price variables: " + exception.getMessage()
);
}
}
private void removeEntryPriceVariables() {
variables.remove("SOL_LONG_ENTRY_PRICE");
variables.remove("SOL_SHORT_ENTRY_PRICE");
variables.remove("BTC_LONG_ENTRY_PRICE");
variables.remove("BTC_SHORT_ENTRY_PRICE");
variables.remove("ETH_LONG_ENTRY_PRICE");
variables.remove("ETH_SHORT_ENTRY_PRICE");
private Map<String, String> copyPriceVariables() {
Map<String, String> previousPriceVariables = new HashMap<>();
for (String variableName : PRICE_VARIABLE_NAMES) {
String value = variables.get(variableName);
if (value != null) {
previousPriceVariables.put(variableName, value);
}
}
return previousPriceVariables;
}
private void removePriceVariables() {
for (String variableName : PRICE_VARIABLE_NAMES) {
variables.remove(variableName);
}
}
private void putPriceVariable(
Map<String, String> previousPriceVariables,
String variableName,
String variableValue
) {
String previousValue = previousPriceVariables.get(variableName);
variables.put(variableName, variableValue);
if (previousValue == null || !previousValue.equals(variableValue)) {
System.out.println(
"{{" + variableName + "}} updated from " +
previousValue +
" --> " +
variableValue
);
}
}
private static String createEntryPriceVariableName(JupiterPerpsPosition position) {
return createPriceVariableName(position, "ENTRY_PRICE");
}
private static String createLiquidationPriceVariableName(JupiterPerpsPosition position) {
return createPriceVariableName(position, "LIQ_PRICE");
}
private static String createPriceVariableName(
JupiterPerpsPosition position,
String suffix
) {
String asset = switch (position.tradedTokenMint()) {
case "So11111111111111111111111111111111111111112" -> "SOL";
case "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh" -> "BTC";
@@ -79,9 +167,45 @@ public final class JupiterPerpsEntryPriceVariableRefresher {
);
};
return asset + "_" + position.direction() + "_ENTRY_PRICE";
return asset + "_" + position.direction() + "_" + suffix;
}
private static final Set<String> PRICE_VARIABLE_NAMES = Set.of(
"SOL_LONG_ENTRY_PRICE",
"SOL_SHORT_ENTRY_PRICE",
"BTC_LONG_ENTRY_PRICE",
"BTC_SHORT_ENTRY_PRICE",
"ETH_LONG_ENTRY_PRICE",
"ETH_SHORT_ENTRY_PRICE",
"SOL_LONG_LIQ_PRICE",
"SOL_SHORT_LIQ_PRICE",
"BTC_LONG_LIQ_PRICE",
"BTC_SHORT_LIQ_PRICE",
"ETH_LONG_LIQ_PRICE",
"ETH_SHORT_LIQ_PRICE"
);
private void refreshPeriodically() {
try {
refresh();
} catch (RuntimeException exception) {
System.err.println(
"Unexpected error during periodic Jupiter Perps price variable refresh: "
+ exception.getMessage()
);
exception.printStackTrace(System.err);
}
}
private static final ΩsecondsΩ REFRESH_INTERVAL_SECONDS = 60;
private final ScheduledExecutorService scheduler;
private final Map<String, String> variables;
private final JupiterPerpsService jupiterPerpsService;
}