implemented modify order size (global and per trader)

This commit is contained in:
Nicolás Sánchez 2025-09-06 18:28:26 -03:00
parent d621c5bf4a
commit 8d3478820e
10 changed files with 187 additions and 4 deletions

View File

@ -7,6 +7,7 @@ import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.example.dcav2gui.ui.exchanges.WorkerData; import com.example.dcav2gui.ui.exchanges.WorkerData;
import com.google.gson.Gson;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
@ -21,8 +22,10 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import okhttp3.MediaType;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response; import okhttp3.Response;
@ -379,6 +382,45 @@ public class InstanceInterface {
} }
} }
public static JsonObject modDefaultOrderSize(String exchange, double newOrderSize, boolean retry) throws IOException {
Gson gson = new Gson();
JsonObject jsonPayload = new JsonObject();
jsonPayload.addProperty("amount", String.valueOf(newOrderSize));
String jsonPayloadString = gson.toJson(jsonPayload);
RequestBody requestBody = RequestBody.create(jsonPayloadString, MediaType.get("application/json; charset=utf-8"));
Request modDefaultOrderSizeRequest = new Request.Builder()
.url(API_BASE_URL + "/" + exchange + "/mod_default_order_size")
.header("X-API-KEY", API_KEY)
.post(requestBody)
.build();
try (Response modDefaultOrderSizeResponse = httpClient.newCall(modDefaultOrderSizeRequest).execute()) {
if (!modDefaultOrderSizeResponse.isSuccessful()) {
if (modDefaultOrderSizeResponse.code() == 503 && retry) {
return modDefaultOrderSize(exchange, newOrderSize,false);
}
throw new IOException("Unexpected code " + modDefaultOrderSizeResponse);
}
String modDefaultOrderSizeResponseBody = modDefaultOrderSizeResponse.body().string();
JsonElement jsonElement = JsonParser.parseString(modDefaultOrderSizeResponseBody);
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 Error");
return jsonObject;
}
//If no error, the response is {"Success": f"Success. Default order size modified to $amount}"}
return jsonObject;
}
}
public static String getAllLogs(String exchange, boolean retry) throws IOException { public static String getAllLogs(String exchange, boolean retry) throws IOException {
//200 lines hard limit //200 lines hard limit
Request logRequest = new Request.Builder() Request logRequest = new Request.Builder()

View File

@ -694,6 +694,50 @@ public class WorkerInterface {
} }
public static JsonObject modOrderSize(String exchange, String pair, double newOrderSize, boolean retry) throws IOException {
String[] pairBaseAndQuote = pair.split("/");
String base = pairBaseAndQuote[0];
String quote = pairBaseAndQuote[1];
Gson gson = new Gson();
JsonObject jsonPayload = new JsonObject();
jsonPayload.addProperty("base", base);
jsonPayload.addProperty("quote", quote);
jsonPayload.addProperty("amount", String.valueOf(newOrderSize));
String jsonPayloadString = gson.toJson(jsonPayload);
RequestBody requestBody = RequestBody.create(jsonPayloadString, MediaType.get("application/json; charset=utf-8"));
Request modOrderSizeRequest = new Request.Builder()
.url(API_BASE_URL + "/" + exchange + "/mod_order_size")
.header("X-API-KEY", API_KEY)
.post(requestBody)
.build();
try (Response modOrderSizeResponse = httpClient.newCall(modOrderSizeRequest).execute()) {
if (!modOrderSizeResponse.isSuccessful()) {
if (modOrderSizeResponse.code() == 503 && retry) {
return modOrderSize(exchange, pair, newOrderSize,false);
}
throw new IOException("Unexpected code " + modOrderSizeResponse);
}
String modOrderSizeResponseBody = modOrderSizeResponse.body().string();
JsonElement jsonElement = JsonParser.parseString(modOrderSizeResponseBody);
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 Error");
return jsonObject;
}
//If no error, the response is {"Success": "Success. The change will take effect when the next deal is started"}
return jsonObject;
}
}
public static JsonObject addSafetyOrders(String exchange, String pair, int amount, boolean retry) throws IOException { public static JsonObject addSafetyOrders(String exchange, String pair, int amount, boolean retry) throws IOException {
String[] pairBaseAndQuote = pair.split("/"); String[] pairBaseAndQuote = pair.split("/");
String base = pairBaseAndQuote[0]; String base = pairBaseAndQuote[0];
@ -1113,6 +1157,42 @@ public class WorkerInterface {
} }
public static void sendModifyOrderSizeCall(String exchange, String pair, Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Modify order size of "+ pair);
final EditText input = new EditText(context);
input.setInputType(InputType.TYPE_CLASS_NUMBER);
input.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
builder.setView(input);
builder.setPositiveButton("Modify", (dialog, which) -> {
final double newOrderSize = Double.parseDouble(input.getText().toString());
new Thread(() -> {
try {
JsonObject response = WorkerInterface.modOrderSize(exchange, pair, newOrderSize, true);
new Handler(Looper.getMainLooper()).post(() -> {
showToggleDialog(response, context);
});
} catch (IOException e) {
e.printStackTrace();
// Show an error dialog on the main thread
new Handler(Looper.getMainLooper()).post(() -> {
AlertDialog.Builder errorBuilder = new AlertDialog.Builder(context);
errorBuilder.setTitle("Error");
errorBuilder.setMessage("Failed to modify order size: " + e.getMessage());
errorBuilder.setPositiveButton("OK", null);
errorBuilder.show();
});
}
}).start();
});
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel());
builder.show();
}
public static void sendAddSafetyOrdersCall(String exchange, String pair, Context context) { public static void sendAddSafetyOrdersCall(String exchange, String pair, Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(context); AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Add safety orders to "+ pair); builder.setTitle("Add safety orders to "+ pair);

View File

@ -103,6 +103,9 @@ public class BinanceFragment extends Fragment implements WorkerCardAdapter.OnCar
} else if (item.getItemId() == R.id.modConcurrentSafetyOrders) { } else if (item.getItemId() == R.id.modConcurrentSafetyOrders) {
WorkerInterface.sendModifyConcurrentSafetyOrdersCall("binance", pair, getContext()); WorkerInterface.sendModifyConcurrentSafetyOrdersCall("binance", pair, getContext());
return true; return true;
} else if (item.getItemId() == R.id.modOrderSize) {
WorkerInterface.sendModifyOrderSizeCall("binance", pair, getContext());
return true;
} else if (item.getItemId() == R.id.addSafetyOrders) { } else if (item.getItemId() == R.id.addSafetyOrders) {
WorkerInterface.sendAddSafetyOrdersCall("binance", pair, getContext()); WorkerInterface.sendAddSafetyOrdersCall("binance", pair, getContext());
return true; return true;

View File

@ -100,7 +100,10 @@ public class GateioFragment extends Fragment implements WorkerCardAdapter.OnCard
WorkerInterface.sendSwitchQuoteCurrencyCall("gateio", pair, getContext()); WorkerInterface.sendSwitchQuoteCurrencyCall("gateio", pair, getContext());
return true; return true;
} else if (item.getItemId() == R.id.modConcurrentSafetyOrders) { } else if (item.getItemId() == R.id.modConcurrentSafetyOrders) {
WorkerInterface.sendModifyConcurrentSafetyOrdersCall("binance", pair, getContext()); WorkerInterface.sendModifyConcurrentSafetyOrdersCall("gateio", pair, getContext());
return true;
} else if (item.getItemId() == R.id.modOrderSize) {
WorkerInterface.sendModifyOrderSizeCall("gateio", pair, getContext());
return true; return true;
} else if (item.getItemId() == R.id.addSafetyOrders) { } else if (item.getItemId() == R.id.addSafetyOrders) {
WorkerInterface.sendAddSafetyOrdersCall("gateio", pair, getContext()); WorkerInterface.sendAddSafetyOrdersCall("gateio", pair, getContext());

View File

@ -100,7 +100,10 @@ public class KucoinFragment extends Fragment implements WorkerCardAdapter.OnCard
WorkerInterface.sendSwitchQuoteCurrencyCall("kucoin", pair, getContext()); WorkerInterface.sendSwitchQuoteCurrencyCall("kucoin", pair, getContext());
return true; return true;
} else if (item.getItemId() == R.id.modConcurrentSafetyOrders) { } else if (item.getItemId() == R.id.modConcurrentSafetyOrders) {
WorkerInterface.sendModifyConcurrentSafetyOrdersCall("binance", pair, getContext()); WorkerInterface.sendModifyConcurrentSafetyOrdersCall("kucoin", pair, getContext());
return true;
} else if (item.getItemId() == R.id.modOrderSize) {
WorkerInterface.sendModifyOrderSizeCall("kucoin", pair, getContext());
return true; return true;
} else if (item.getItemId() == R.id.addSafetyOrders) { } else if (item.getItemId() == R.id.addSafetyOrders) {
WorkerInterface.sendAddSafetyOrdersCall("kucoin", pair, getContext()); WorkerInterface.sendAddSafetyOrdersCall("kucoin", pair, getContext());

View File

@ -100,7 +100,10 @@ public class OkxFragment extends Fragment implements WorkerCardAdapter.OnCardLon
WorkerInterface.sendSwitchQuoteCurrencyCall("okex", pair, getContext()); WorkerInterface.sendSwitchQuoteCurrencyCall("okex", pair, getContext());
return true; return true;
} else if (item.getItemId() == R.id.modConcurrentSafetyOrders) { } else if (item.getItemId() == R.id.modConcurrentSafetyOrders) {
WorkerInterface.sendModifyConcurrentSafetyOrdersCall("binance", pair, getContext()); WorkerInterface.sendModifyConcurrentSafetyOrdersCall("okex", pair, getContext());
return true;
} else if (item.getItemId() == R.id.modOrderSize) {
WorkerInterface.sendModifyOrderSizeCall("okex", pair, getContext());
return true; return true;
} else if (item.getItemId() == R.id.addSafetyOrders) { } else if (item.getItemId() == R.id.addSafetyOrders) {
WorkerInterface.sendAddSafetyOrdersCall("okex", pair, getContext()); WorkerInterface.sendAddSafetyOrdersCall("okex", pair, getContext());

View File

@ -1,13 +1,16 @@
package com.example.dcav2gui.ui.home; package com.example.dcav2gui.ui.home;
import static com.example.dcav2gui.InstanceInterface.getLastNTrades; import static com.example.dcav2gui.InstanceInterface.getLastNTrades;
import static com.example.dcav2gui.WorkerInterface.showToggleDialog;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Color; import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.text.InputType;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
@ -16,6 +19,7 @@ import android.view.LayoutInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.PopupMenu; import android.widget.PopupMenu;
@ -34,6 +38,7 @@ import com.example.dcav2gui.InstanceInterface;
import com.example.dcav2gui.MainActivity; import com.example.dcav2gui.MainActivity;
import com.example.dcav2gui.R; import com.example.dcav2gui.R;
import com.example.dcav2gui.TickerTracker; import com.example.dcav2gui.TickerTracker;
import com.example.dcav2gui.WorkerInterface;
import com.example.dcav2gui.ui.exchanges.adapters.WorkerCardAdapter; import com.example.dcav2gui.ui.exchanges.adapters.WorkerCardAdapter;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
@ -348,6 +353,9 @@ public class HomeFragment extends Fragment {
} else if (item.getItemId() == R.id.exchangeMenuConfigFile) { } else if (item.getItemId() == R.id.exchangeMenuConfigFile) {
fetchExchangeConfig(exchange, true); fetchExchangeConfig(exchange, true);
return true; return true;
} else if (item.getItemId() == R.id.exchangeModDefaultOrderSize) {
sendModifyDefaultOrderSizeCall(exchange, getContext());
return true;
} }
return false; return false;
} }
@ -540,6 +548,43 @@ public class HomeFragment extends Fragment {
return shortWorkers; return shortWorkers;
} }
public static void sendModifyDefaultOrderSizeCall(String exchange, Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Modify default order size of "+ exchange);
final EditText input = new EditText(context);
input.setInputType(InputType.TYPE_CLASS_NUMBER);
input.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
builder.setView(input);
builder.setPositiveButton("Modify", (dialog, which) -> {
final double newOrderSize = Double.parseDouble(input.getText().toString());
new Thread(() -> {
try {
JsonObject response = InstanceInterface.modDefaultOrderSize(exchange, newOrderSize, true);
new Handler(Looper.getMainLooper()).post(() -> {
showToggleDialog(response, context);
});
} catch (IOException e) {
e.printStackTrace();
// Show an error dialog on the main thread
new Handler(Looper.getMainLooper()).post(() -> {
AlertDialog.Builder errorBuilder = new AlertDialog.Builder(context);
errorBuilder.setTitle("Error");
errorBuilder.setMessage("Failed to modify default order size: " + e.getMessage());
errorBuilder.setPositiveButton("OK", null);
errorBuilder.show();
});
}
}).start();
});
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel());
builder.show();
}
private void showLastTradesDetailsDialog(List<InstanceInterface.DealData> result) { private void showLastTradesDetailsDialog(List<InstanceInterface.DealData> result) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
List<String> shortWorkers = new ArrayList<>(); List<String> shortWorkers = new ArrayList<>();

View File

@ -12,4 +12,6 @@
android:title="View paused traders" /> android:title="View paused traders" />
<item android:id="@+id/exchangeMenuConfigFile" <item android:id="@+id/exchangeMenuConfigFile"
android:title="View config file" /> android:title="View config file" />
<item android:id="@+id/exchangeModDefaultOrderSize"
android:title="Modify default order size" />
</menu> </menu>

View File

@ -42,6 +42,8 @@
<item android:id="@+id/workerMenuAdd" <item android:id="@+id/workerMenuAdd"
android:title="Add..."> android:title="Add...">
<menu> <menu>
<item android:id="@+id/modOrderSize"
android:title="Modify order size"/>
<item android:id="@+id/modConcurrentSafetyOrders" <item android:id="@+id/modConcurrentSafetyOrders"
android:title="Modify concurrent safety orders"/> android:title="Modify concurrent safety orders"/>
<item android:id="@+id/addSafetyOrders" <item android:id="@+id/addSafetyOrders"

View File

@ -1,7 +1,7 @@
<resources> <resources>
<string name="app_name" translatable="false">DCAv2GUI</string> <string name="app_name" translatable="false">DCAv2GUI</string>
<string name="nav_header_title" translatable="false">DCAv2</string> <string name="nav_header_title" translatable="false">DCAv2</string>
<string name="nav_header_subtitle">Version 2025.09.05</string> <string name="nav_header_subtitle">Version 2025.09.06</string>
<string name="navigation_drawer_open">Open navigation drawer</string> <string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string> <string name="navigation_drawer_close">Close navigation drawer</string>
<string name="nav_header_desc">Navigation header</string> <string name="nav_header_desc">Navigation header</string>