exchange popup menu mostly implemented

This commit is contained in:
Nicolás Sánchez 2024-12-23 11:20:40 -03:00
parent 25cbf1615f
commit ad636a445c
5 changed files with 232 additions and 17 deletions

View File

@ -4,7 +4,7 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2024-12-19T12:29:08.104137914Z">
<DropdownSelection timestamp="2024-12-23T10:34:33.165240137Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/home/nicolas/.android/avd/Pixel_6_Pro_API_34.avd" />

View File

@ -2,6 +2,8 @@ package com.example.dcav2gui;
import static com.example.dcav2gui.MainActivity.globalSettings;
import androidx.annotation.NonNull;
import com.example.dcav2gui.ui.exchanges.WorkerData;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@ -129,6 +131,40 @@ public class InstanceInterface {
}
}
public static double getServerTime(String exchange, boolean retry) throws IOException {
Request serverTimeRequest = new Request.Builder()
.url(API_BASE_URL + "/" + exchange + "/server_time")
.header("X-API-KEY", API_KEY)
.build();
try (Response serverTimeResponse = httpClient.newCall(serverTimeRequest).execute()) {
if (!serverTimeResponse.isSuccessful()) {
if (serverTimeResponse.code() == 503 && retry) {
return getServerTime(exchange,false);
}
throw new IOException("Unexpected code " + serverTimeResponse);
}
String serverTimeResponseBody = serverTimeResponse.body().string();
try {
JsonElement jsonElement = JsonParser.parseString(serverTimeResponseBody);
if (!jsonElement.isJsonObject()) {
System.err.println("The parsed JSON response is not a JsonObject.");
return 0.0;
}
JsonObject jsonObject = jsonElement.getAsJsonObject();
if (jsonObject.has("Time")) {
return jsonObject.get("Time").getAsDouble();
} else {
System.err.println("The parsed JSON response does not contain a 'Time' entry.");
return 0.0;
}
} catch (Exception e) {
System.err.println("Error querying server time: " + e.getMessage());
return 0.0;
}
}
}
public static List<DealData> getAllTrades() throws IOException {
@ -374,6 +410,45 @@ public class InstanceInterface {
}
}
public static List<String> getMissingPairs(String exchange, boolean retry) throws IOException {
List<String> valueToReturn = new ArrayList<>();
Request missingPairsRequest = new Request.Builder()
.url(API_BASE_URL + "/" + exchange + "/missing_pairs")
.header("X-API-KEY", API_KEY)
.build();
try (Response missingPairsResponse = httpClient.newCall(missingPairsRequest).execute()) {
if (!missingPairsResponse.isSuccessful()) {
if (missingPairsResponse.code() == 503 && retry) {
return getMissingPairs(exchange, false);
}
throw new IOException("Unexpected code " + missingPairsResponse);
}
String missingPairsResponseBody = missingPairsResponse.body().string();
JsonElement jsonElement = JsonParser.parseString(missingPairsResponseBody);
if (!jsonElement.isJsonObject()) {
System.err.println("The parsed JSON response is not a JsonObject.");
return null;
}
JsonObject jsonObject = jsonElement.getAsJsonObject();
if (jsonObject.has("Error")) {
System.err.println("The parsed JSON response contains an Error field");
return null;
}
if (jsonObject.has("MissingPairs")) {
//Parse the string as a Json array and add it to response
JsonArray jsonArray = jsonObject.getAsJsonArray("MissingPairs");
for (JsonElement jsonElement1 : jsonArray) {
String missingPair = jsonElement1.getAsString();
valueToReturn.add(missingPair);
}
}
return valueToReturn;
}
}
public static List<WorkerStatsData> getAllWorkersStats(String exchange, boolean retry) throws IOException {
List<WorkerStatsData> valueToReturn = new ArrayList<>();
@ -510,15 +585,12 @@ public class InstanceInterface {
}
private static InstanceGlobalStatsData getInstanceGlobalStatus(String exchange, boolean retry) throws IOException {
List<WorkerStatsData> valueToReturn = new ArrayList<>();
public static InstanceGlobalStatsData getInstanceGlobalStatus(String exchange, boolean retry) throws IOException {
Request globalStatsRequest = new Request.Builder()
.url(API_BASE_URL + "/" + exchange + "/global_status")
.header("X-API-KEY", API_KEY)
.build();
try (Response globalStatsResponse = httpClient.newCall(globalStatsRequest).execute()) {
if (!globalStatsResponse.isSuccessful()) {
if (globalStatsResponse.code() == 503 && retry) {
@ -539,7 +611,6 @@ public class InstanceInterface {
JsonObject jsonObject = jsonElement.getAsJsonObject();
// Extracting online_workers and paused_traders from the response
JsonArray onlineWorkersJsonArray = jsonObject.get("online_workers").getAsJsonArray();
List<String> onlineWorkers = new ArrayList<>();
@ -620,7 +691,6 @@ public class InstanceInterface {
workerStatsData.getIsShort(),
workerStatsData.getIsBoosted(),
workerStatsData.getAutoSwitchEnabled(),
//Let's deal with this later
workerStatsData.getIsPaused(),
workerStatsData.getStopWhenProfit(),
workerStatsData.getOldLongDictionary());
@ -732,6 +802,22 @@ public class InstanceInterface {
public Boolean getAttemptToRestart() { return attemptToRestart; }
public double getDefaultOrderSize() { return defaultOrderSize; }
public Boolean getUnifiedOrderQuery() { return unifiedOrderQuery; }
@NonNull
@Override
public String toString() {
return "Name: " + brokerName + "\n" +
"Testnet: " + isSandbox.toString() + "\n" +
"Simulate market orders: " + simulateMarketOrders.toString() + "\n" +
"Pairs: " + pairs + "\n" +
"Lap time: " + laptime + " seconds \n" +
"Cooldown multiplier: " + cooldownMultiplier + "\n" +
"Wait time before a new safety order: " + waitBeforeNewSafetyOrder + "\n" +
"Telegram: " + sendTelegram.toString() + "\n" +
"Restart: " + attemptToRestart.toString() + "\n" +
"Default order size: " + defaultOrderSize + "\n" +
"Unified order query: " + unifiedOrderQuery;
}
}

View File

@ -49,6 +49,7 @@ public class BinanceViewModel extends AndroidViewModel {
} catch (IOException e) {
e.printStackTrace();
}
// Schedule the next execution
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override

View File

@ -1,9 +1,11 @@
package com.example.dcav2gui.ui.home;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
@ -31,6 +33,7 @@ import com.example.dcav2gui.MainActivity;
import com.example.dcav2gui.R;
import com.example.dcav2gui.TickerTracker;
import com.example.dcav2gui.databinding.FragmentHomeBinding;
import com.example.dcav2gui.ui.exchanges.adapters.WorkerCardAdapter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@ -327,22 +330,22 @@ public class HomeFragment extends Fragment {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.exchangeMenuGlobalStatus) {
// Handle the "Details..." option
// For example, navigate to a details fragment
fetchExchangeDetails(exchange);
return true;
} else if (item.getItemId() == R.id.exchangeMenuMissingPairs) {
fetchMissingPairs(exchange);
return true;
} else if (item.getItemId() == R.id.exchangeMenuServerTime) {
fetchServerTime(exchange);
return true;
} else if (item.getItemId() == R.id.exchangeMenuTraderTime) {
fetchTraderTime(exchange);
return true;
} else if (item.getItemId() == R.id.exchangeMenuPausedTraders) {
fetchPausedTraders(exchange);
return true;
} else if (item.getItemId() == R.id.exchangeMenuConfigFile) {
return true;
} else if (item.getItemId() == R.id.exchangeMenuBacktests) {
return true;
} else if (item.getItemId() == R.id.exchangeMenuGetBalance) {
fetchExchangeConfig(exchange);
return true;
}
return false;
@ -408,6 +411,135 @@ public class HomeFragment extends Fragment {
}
}
private void fetchExchangeDetails(String exchange) {
new Thread(() -> {
try {
InstanceInterface.InstanceGlobalStatsData result = InstanceInterface.getInstanceGlobalStatus(exchange, true);
new Handler(Looper.getMainLooper()).post(() -> showInstanceDetailsDialog(result));
} catch (IOException e) {
e.printStackTrace();
new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(getContext(), "Failed to fetch details", Toast.LENGTH_SHORT).show());
}
}).start();
}
private void fetchPausedTraders(String exchange) {
new Thread(() -> {
try {
InstanceInterface.InstanceGlobalStatsData result = InstanceInterface.getInstanceGlobalStatus(exchange, true);
new Handler(Looper.getMainLooper()).post(() -> showPausedTradersDialog(result));
} catch (IOException e) {
e.printStackTrace();
new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(getContext(), "Failed to fetch details", Toast.LENGTH_SHORT).show());
}
}).start();
}
private void fetchMissingPairs(String exchange) {
new Thread(() -> {
try {
List<String> result = InstanceInterface.getMissingPairs(exchange, true);
new Handler(Looper.getMainLooper()).post(() -> showMissingPairsDialog(result));
} catch (IOException e) {
e.printStackTrace();
new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(getContext(), "Failed to fetch missing pairs", Toast.LENGTH_SHORT).show());
}
}).start();
}
private void fetchServerTime(String exchange) {
new Thread(() -> {
try {
double result = InstanceInterface.getServerTime(exchange, true);
new Handler(Looper.getMainLooper()).post(() -> showServerTimeDialog(result));
} catch (IOException e) {
e.printStackTrace();
new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(getContext(), "Failed to fetch missing pairs", Toast.LENGTH_SHORT).show());
}
}).start();
}
private void fetchTraderTime(String exchange) {
new Thread(() -> {
try {
double result = InstanceInterface.getTraderTime(exchange, true);
new Handler(Looper.getMainLooper()).post(() -> showTraderTimeDialog(result));
} catch (IOException e) {
e.printStackTrace();
new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(getContext(), "Failed to fetch missing pairs", Toast.LENGTH_SHORT).show());
}
}).start();
}
private void fetchExchangeConfig(String exchange) {
new Thread(() -> {
try {
InstanceInterface.InstanceGlobalStatsData result = InstanceInterface.getInstanceGlobalStatus(exchange, true);
new Handler(Looper.getMainLooper()).post(() -> showInstanceConfigDialog(result));
} catch (IOException e) {
e.printStackTrace();
new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(getContext(), "Failed to fetch details", Toast.LENGTH_SHORT).show());
}
}).start();
}
private void showInstanceDetailsDialog(InstanceInterface.InstanceGlobalStatsData result) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(result.getName() + " details");
builder.setMessage("Instance uptime: " + WorkerCardAdapter.formatSeconds(result.getUptime()) + "\n" +
"Online traders: " + result.getOnlineWorkers().size() + "\n" +
"Paused traders: " + result.getPausedTraders().size() + "\n" +
"DCAv2 version: " + result.getVersion() + "\n" +
"CCXT version: " + result.getCcxtVersion());
builder.setPositiveButton("OK", null);
builder.show();
}
private void showPausedTradersDialog(InstanceInterface.InstanceGlobalStatsData result) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Paused traders:");
builder.setMessage(result.getPausedTraders().toString());
builder.setPositiveButton("OK", null);
builder.show();
}
private void showInstanceConfigDialog(InstanceInterface.InstanceGlobalStatsData result) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(result.getName() + " config:");
builder.setMessage(result.getConfig().toString());
builder.setPositiveButton("OK", null);
builder.show();
}
private void showMissingPairsDialog(List<String> missingPairs) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Missing pairs");
if (missingPairs.isEmpty()) {
builder.setMessage("No missing traders");
} else {
builder.setMessage(String.valueOf(missingPairs));
}
builder.setPositiveButton("OK", null);
builder.show();
}
private void showServerTimeDialog(double serverTime) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Server time");
builder.setMessage(timeStampConverter(serverTime));
builder.setPositiveButton("OK", null);
builder.show();
}
private void showTraderTimeDialog(double traderTime) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Trader time");
builder.setMessage(timeStampConverter(traderTime));
builder.setPositiveButton("OK", null);
builder.show();
}
private void fetchAndDisplayData() {
// For the cache
MainActivity mainActivity = (MainActivity) requireActivity();

View File

@ -12,8 +12,4 @@
android:title="View paused traders" />
<item android:id="@+id/exchangeMenuConfigFile"
android:title="View config file" />
<item android:id="@+id/exchangeMenuBacktests"
android:title="Backtests" />
<item android:id="@+id/exchangeMenuGetBalance"
android:title="Get balance" />
</menu>