Multi-Charts: Wie mit 0-Werten umgehen?



  • Hallo, noch ein Thema von mir, aber hoffentlich nun (vorerst) das letzte ...

    Ich habe mir ein Backend-Tool geschrieben, das nur die Aufgabe hat, den aktuellen Kontostand bei binance zu erfragen, der dann später in einem Multi-Linechart dargestellt werden soll. Bei binance (ich nutze die offizielle Api-Lib für Java) geht das aber nur, indem man alle Assets erfragt, und jeweils deren aktuellen Wert (zum Beispiel in $) ermittelt und zusammenaddiert.

    So weit, so gut. Die Werte sollen fürs Frontend später in .json-Dateien geschrieben werden. Mit JavaScript kann ich dann die Charts plotten. Das Problem dabei ist, dass es am 14.7. Asset x geben kann, welches am 15.7. wieder verkauft wird. Wie soll ich das darstellen?

    Wenn ich das if in Zeile 69 einfach auskommentiere, dann werden alle Assets, die angeboten werden, gespeichert. Ich möchte aber nur alle Assets speichern, deren Menge schon einmal != 0 gewesen ist ... Habt ihr da eine Idee?

    package org.example;
    
    import com.google.gson.JsonArray;
    import com.google.gson.JsonElement;
    import com.google.gson.JsonObject;
    import com.google.gson.JsonParser;
    import com.webcerebrium.binance.api.BinanceApi;
    import com.webcerebrium.binance.api.BinanceApiException;
    import com.webcerebrium.binance.datatype.BinanceWalletAsset;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.math.BigDecimal;
    import java.nio.charset.Charset;
    import java.util.ArrayList;
    import java.util.DoubleSummaryStatistics;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class Main {
        public static final String DIR_NAME = "website/json-data/";
    
        public record MyAsset(
                long time1,
                String pair,
                BigDecimal free,
                BigDecimal locked,
                BigDecimal price,
                BigDecimal usd) {}
    
        public static BinanceApi getApi() throws BinanceApiException, Exception {
            File file = new File("my_api.txt");
            if (!file.exists()) {
                return new BinanceApi();
            }
            String key, secret;
            try (BufferedReader br =
                    new BufferedReader(new FileReader(file, Charset.defaultCharset()))) {
                key = br.readLine();
                secret = br.readLine();
            }
            return new BinanceApi(key, secret);
        }
    
        public static JsonArray getJsonArray(File fn) throws IOException {
            if (fn.exists()) {
                try (BufferedReader br =
                        new BufferedReader(new FileReader(fn, Charset.defaultCharset()))) {
                    return new JsonParser().parse(br).getAsJsonArray();
                }
            } else {
                return new JsonArray();
            }
        }
    
        public static Map<String, MyAsset> collect() throws BinanceApiException, Exception {
            BinanceApi api = getApi();
            Map<String, BinanceWalletAsset> balances = api.balancesMap();
            Map<String, BigDecimal> prices = api.pricesMap();
            Map<String, MyAsset> newBalances = new HashMap<>();
            final long t1 = System.currentTimeMillis();
            for (BinanceWalletAsset bwa : balances.values()) {
                if (bwa.getFree().compareTo(BigDecimal.ZERO) > 0) {
                    if (!bwa.getAsset().equals("USDT")) {
                        String pair = bwa.getAsset() + "USDT";
                        if (prices.containsKey(pair)) {
                            BigDecimal free = bwa.getFree();
                            BigDecimal locked = bwa.getLocked();
                            BigDecimal price = prices.get(pair);
                            BigDecimal usd = free.add(locked).multiply(price);
                            newBalances.put(pair, new MyAsset(t1, pair, free, locked, price, usd));
                        }
                    }
                }
            }
            System.out.println("newBalances = " + newBalances);
            return newBalances;
        }
    
        public static void writeJson(Map<String, MyAsset> newBalances) throws IOException {
            long time1 = newBalances.values().stream().findFirst().orElseThrow().time1();
            {
                JsonArray sums = getJsonArray(new File(DIR_NAME + "sums.json"));
                float sum = 0;
                for (MyAsset ma : newBalances.values()) {
                    sum += ma.usd().floatValue();
                }
                JsonObject o = new JsonObject();
                o.addProperty("x", time1);
                o.addProperty("y", sum);
                sums.add(o);
                try (FileWriter fw = new FileWriter(DIR_NAME + "sums.json", Charset.defaultCharset())) {
                    fw.write(sums.toString());
                }
            }
    
            for (MyAsset ma : newBalances.values()) {
                JsonArray data = getJsonArray(new File(DIR_NAME + ma.pair() + ".json"));
                JsonObject o = new JsonObject();
                o.addProperty("x", time1);
                o.addProperty("y", ma.usd().floatValue());
                data.add(o);
                try (FileWriter fw =
                        new FileWriter(DIR_NAME + ma.pair() + ".json", Charset.defaultCharset())) {
                    fw.write(data.toString());
                }
            }
        }
    
        public static void normalizeJsonData() throws IOException {
            final long one_hour = 1000 * 60 * 60;
            final long two_hours = 1000 * 60 * 60 * 2;
            File dir = new File(DIR_NAME);
            File[] files = dir.listFiles();
            assert files != null;
            for (File file : files) {
                JsonArray array = getJsonArray(file);
                long start =
                        array.get(0).getAsJsonObject().get("x").getAsLong() / two_hours * two_hours;
                long stop = start + two_hours;
                List<List<JsonObject>> chunks = new ArrayList<>();
                List<JsonObject> newChunks = new ArrayList<>();
                Iterator<JsonElement> iterator1 = array.iterator();
                while (iterator1.hasNext()) {
                    JsonObject jo = iterator1.next().getAsJsonObject();
                    long x = jo.get("x").getAsLong();
                    if (x >= start && x < stop) {
                        newChunks.add(jo);
                    } else {
                        chunks.add(newChunks);
                        newChunks = new ArrayList<>();
                        newChunks.add(jo);
                        start = stop;
                        stop = stop + two_hours;
                    }
                    if (!iterator1.hasNext()) {
                        // last element
                        chunks.add(newChunks);
                    }
                }
    
                JsonArray newArray = new JsonArray();
                Iterator<List<JsonObject>> iterator2 = chunks.iterator();
                while (iterator2.hasNext()) {
                    List<JsonObject> chunk = iterator2.next();
                    if (iterator2.hasNext()) {
                        // not last element
                        DoubleSummaryStatistics statistics =
                                chunk.stream()
                                        .mapToDouble(jo -> jo.get("y").getAsFloat())
                                        .summaryStatistics();
                        double min = statistics.getMin();
                        double max = statistics.getMax();
                        double avr = statistics.getAverage();
                        double newY = Math.abs(min - avr) >= Math.abs(max - avr) ? min : max;
                        long newX =
                                chunk.get(0).getAsJsonObject().get("x").getAsLong()
                                                / two_hours
                                                * two_hours
                                        + one_hour;
                        JsonObject newObj = new JsonObject();
                        newObj.addProperty("x", newX);
                        newObj.addProperty("y", (float) newY);
                        newArray.add(newObj);
                    } else {
                        // last element
                        for (JsonObject jo : chunk) {
                            newArray.add(jo);
                        }
                    }
                }
    
                try (FileWriter fw = new FileWriter(file, Charset.defaultCharset())) {
                    fw.write(newArray.toString());
                }
            }
        }
    
        public static void main(String[] args) {
            if (!new File(DIR_NAME).exists()) {
                System.out.println("new File(DIR_NAME).mkdir() = " + new File(DIR_NAME).mkdir());
            }
            Timer timer = new Timer();
            timer.schedule(
                    new TimerTask() {
                        @Override
                        public void run() {
                            try {
                                Map<String, MyAsset> newBalances = collect();
                                writeJson(newBalances);
                                normalizeJsonData();
                            } catch (BinanceApiException | Exception e) {
                                e.printStackTrace();
                                System.err.println(e.getMessage());
                            }
                        }
                    },
                    0,
                    1000 * 60 * 30); // Soll alle 30 Minuten einmal laufen
        }
    }
    


  • Hab es jetzt hinbekommen, mit einer zusätzlichen Liste, die sich alle bereits bekannten Assetnames "merkt".

    Mh, hat das Forum zufällig eine Funktion, um zwei Texte/Codes zu diffen? Das wäre super, um die Unterschiede sichtbar zu machen ...

    package org.example;
    
    import com.google.gson.JsonArray;
    import com.google.gson.JsonElement;
    import com.google.gson.JsonObject;
    import com.google.gson.JsonParser;
    import com.webcerebrium.binance.api.BinanceApi;
    import com.webcerebrium.binance.api.BinanceApiException;
    import com.webcerebrium.binance.datatype.BinanceWalletAsset;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.math.BigDecimal;
    import java.nio.charset.Charset;
    import java.util.ArrayList;
    import java.util.DoubleSummaryStatistics;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class Main {
        public static final String DIR_NAME = "website/json-data/";
        private static final ArrayList<String> KNOWN_ASSET_NAMES = new ArrayList<>();
    
        public record MyAsset(
                long time1,
                String pair,
                BigDecimal free,
                BigDecimal locked,
                BigDecimal price,
                BigDecimal usd) {}
    
        public static void initKnownAssetNames() {
            HashSet<String> assetNames = new HashSet<>();
            File dir = new File(DIR_NAME);
            File[] files = dir.listFiles();
            assert files != null;
            for (File file : files) {
                String fn = file.getName();
                if (fn.endsWith("USDT.json")) {
                    assetNames.add(fn.substring(0, fn.indexOf("USDT.json")));
                }
            }
            KNOWN_ASSET_NAMES.clear();
            KNOWN_ASSET_NAMES.addAll(assetNames);
        }
    
        public static BinanceApi getApi() throws BinanceApiException, Exception {
            File file = new File("my_api.txt");
            if (!file.exists()) {
                return new BinanceApi();
            }
            String key, secret;
            try (BufferedReader br =
                    new BufferedReader(new FileReader(file, Charset.defaultCharset()))) {
                key = br.readLine();
                secret = br.readLine();
            }
            return new BinanceApi(key, secret);
        }
    
        public static JsonArray getJsonArray(File fn) throws IOException {
            if (fn.exists()) {
                try (BufferedReader br =
                        new BufferedReader(new FileReader(fn, Charset.defaultCharset()))) {
                    return new JsonParser().parse(br).getAsJsonArray();
                }
            } else {
                return new JsonArray();
            }
        }
    
        public static Map<String, MyAsset> collect() throws BinanceApiException, Exception {
            BinanceApi api = getApi();
            Map<String, BinanceWalletAsset> balances = api.balancesMap();
            Map<String, BigDecimal> prices = api.pricesMap();
            Map<String, MyAsset> newBalances = new HashMap<>();
            final long t1 = System.currentTimeMillis();
            for (BinanceWalletAsset bwa : balances.values()) {
                if (!bwa.getAsset().equals("USDT")) {
                    if (bwa.getFree().compareTo(BigDecimal.ZERO) > 0) {
                        if (!KNOWN_ASSET_NAMES.contains(bwa.getAsset())) {
                            KNOWN_ASSET_NAMES.add(bwa.getAsset());
                        }
                    }
                    if (KNOWN_ASSET_NAMES.contains(bwa.getAsset())) {
                        String pair = bwa.getAsset() + "USDT";
                        if (prices.containsKey(pair)) {
                            BigDecimal free = bwa.getFree();
                            BigDecimal locked = bwa.getLocked();
                            BigDecimal price = prices.get(pair);
                            BigDecimal usd = free.add(locked).multiply(price);
                            newBalances.put(pair, new MyAsset(t1, pair, free, locked, price, usd));
                        }
                    }
                }
            }
            System.out.println("newBalances = " + newBalances);
            return newBalances;
        }
    
        public static void writeJson(Map<String, MyAsset> newBalances) throws IOException {
            long time1 = newBalances.values().stream().findFirst().orElseThrow().time1();
            {
                JsonArray sums = getJsonArray(new File(DIR_NAME + "sums.json"));
                float sum = 0;
                for (MyAsset ma : newBalances.values()) {
                    sum += ma.usd().floatValue();
                }
                JsonObject o = new JsonObject();
                o.addProperty("x", time1);
                o.addProperty("y", sum);
                sums.add(o);
                try (FileWriter fw = new FileWriter(DIR_NAME + "sums.json", Charset.defaultCharset())) {
                    fw.write(sums.toString());
                }
            }
    
            for (MyAsset ma : newBalances.values()) {
                JsonArray data = getJsonArray(new File(DIR_NAME + ma.pair() + ".json"));
                JsonObject o = new JsonObject();
                o.addProperty("x", time1);
                o.addProperty("y", ma.usd().floatValue());
                data.add(o);
                try (FileWriter fw =
                        new FileWriter(DIR_NAME + ma.pair() + ".json", Charset.defaultCharset())) {
                    fw.write(data.toString());
                }
            }
        }
    
        public static void normalizeJsonData() throws IOException {
            final long one_hour = 1000 * 60 * 60;
            final long two_hours = 1000 * 60 * 60 * 2;
            File dir = new File(DIR_NAME);
            File[] files = dir.listFiles();
            assert files != null;
            for (File file : files) {
                JsonArray array = getJsonArray(file);
                long start =
                        array.get(0).getAsJsonObject().get("x").getAsLong() / two_hours * two_hours;
                long stop = start + two_hours;
                List<List<JsonObject>> chunks = new ArrayList<>();
                List<JsonObject> newChunks = new ArrayList<>();
                Iterator<JsonElement> iterator1 = array.iterator();
                while (iterator1.hasNext()) {
                    JsonObject jo = iterator1.next().getAsJsonObject();
                    long x = jo.get("x").getAsLong();
                    if (x >= start && x < stop) {
                        newChunks.add(jo);
                    } else {
                        chunks.add(newChunks);
                        newChunks = new ArrayList<>();
                        newChunks.add(jo);
                        start = stop;
                        stop = stop + two_hours;
                    }
                    if (!iterator1.hasNext()) {
                        // last element
                        chunks.add(newChunks);
                    }
                }
    
                JsonArray newArray = new JsonArray();
                Iterator<List<JsonObject>> iterator2 = chunks.iterator();
                while (iterator2.hasNext()) {
                    List<JsonObject> chunk = iterator2.next();
                    if (iterator2.hasNext()) {
                        // not last element
                        DoubleSummaryStatistics statistics =
                                chunk.stream()
                                        .mapToDouble(jo -> jo.get("y").getAsFloat())
                                        .summaryStatistics();
                        double min = statistics.getMin();
                        double max = statistics.getMax();
                        double avr = statistics.getAverage();
                        double newY = Math.abs(min - avr) >= Math.abs(max - avr) ? min : max;
                        long newX =
                                chunk.get(0).getAsJsonObject().get("x").getAsLong()
                                                / two_hours
                                                * two_hours
                                        + one_hour;
                        JsonObject newObj = new JsonObject();
                        newObj.addProperty("x", newX);
                        newObj.addProperty("y", (float) newY);
                        newArray.add(newObj);
                    } else {
                        // last element
                        for (JsonObject jo : chunk) {
                            newArray.add(jo);
                        }
                    }
                }
    
                try (FileWriter fw = new FileWriter(file, Charset.defaultCharset())) {
                    fw.write(newArray.toString());
                }
            }
        }
    
        public static void main(String[] args) {
            if (!new File(DIR_NAME).exists()) {
                System.out.println("new File(DIR_NAME).mkdir() = " + new File(DIR_NAME).mkdir());
            }
            initKnownAssetNames();
            Timer timer = new Timer();
            timer.schedule(
                    new TimerTask() {
                        @Override
                        public void run() {
                            try {
                                Map<String, MyAsset> newBalances = collect();
                                writeJson(newBalances);
                                normalizeJsonData();
                            } catch (BinanceApiException | Exception e) {
                                e.printStackTrace();
                                System.err.println(e.getMessage());
                            }
                        }
                    },
                    0,
                    1000 * 60 * 30);
        }
    }
    
    

    KNOWN_ASSET_NAMES ist neu.


Anmelden zum Antworten