Durchschnittliche Volatility in Prozent für 4 Stunden berechnen

vup

Mitglied
Hi, ich wollte mal Fragen, ob das so richtig ist...

Ich versuche, die durchschnittliche Kursvolatility in Prozent mithilfe von 4-Stunden-Kerzen über einen Zeitraum von 1 Monat zu berechnen. Bin mir aber unsicher, ob der Rechenweg so richtig wäre:

Java:
    public static String f(Object dObj) {
        if (dObj instanceof BigDecimal) {
            return ((BigDecimal) dObj).toPlainString();
        }
        return String.format(Locale.ROOT, "%.9f", (double) dObj);
    }

    public static void main(String[] args) throws BinanceApiException {
        SimpleDateFormat sdf = new SimpleDateFormat();
        BinanceApi api = new BinanceApi();
        List<BinanceCandlestick> klines = api.klines(BinanceSymbol.valueOf("ETHBTC"), BinanceInterval.FOUR_HOURS, 31 * 6, null);
        double sumDerivation = 0;
        double sumVolatilityUp = 0;
        double sumVolatilityDown = 0;
        for (int i = 0; i < klines.size(); i++) {
            BinanceCandlestick cs = klines.get(i);
            double derivation = cs.getHigh().doubleValue() - cs.getLow().doubleValue();
            double mid = (cs.getHigh().doubleValue() + cs.getLow().doubleValue()) / 2.0;
            double vUp = cs.getHigh().doubleValue() / mid;
            double vDown = mid / cs.getLow().doubleValue();
            sumDerivation += derivation;
            sumVolatilityUp += vUp;
            sumVolatilityDown += vDown;
            System.out.println((i + 1) + ";" + sdf.format(new Date(cs.getOpenTime())) + ";" + f(cs.getHigh()) + ";" + f(cs.getLow()) + ";" + f(derivation) + ";" + f(vUp) + ";" + f(vDown));
        }
        System.out.println("avgDerivation = " + f(sumDerivation / klines.size()));
        System.out.println("avgVolatilityUp = " + f((sumVolatilityUp / klines.size() - 1) * 100));
        System.out.println("avgVolatilityDown = " + f((sumVolatilityDown / klines.size() - 1) * 100));
    }

Die Ausgabe ist dann in etwa:

Code:
...
181;22.03.23, 13:00;0.06380500;0.06299500;0.000810000;1.006388013;1.006429082
182;22.03.23, 17:00;0.06440300;0.06250100;0.001902000;1.014987707;1.015215757
183;22.03.23, 21:00;0.06438800;0.06320300;0.001185000;1.009287489;1.009374555
184;23.03.23, 01:00;0.06379200;0.06345100;0.000341000;1.002679912;1.002687113
185;23.03.23, 05:00;0.06359100;0.06321100;0.000380000;1.002996798;1.003005806
186;23.03.23, 09:00;0.06344000;0.06334000;0.000100000;1.000788768;1.000789391
avgDerivation = 0.000606113
avgVolatilityUp = 0.445288083
avgVolatilityDown = 0.448367477

Heißt das, der Kurs steigt/absinkt in 4 Stunden durchschnittlich um ca. 0,45 % nach oben bzw. unten? Erfahrungsgemäß müsste das ungefähr passen, bin mir wegen des Rechenwegs aber noch nicht sicher ... :(
 

vup

Mitglied
Huch, in Zeile 5 hat sich noch ein Fehler eingeschlichen (doppeltes Auto-boxing), Korrektur:

Java:
        return String.format(Locale.ROOT, "%.9f", (Double) dObj);

Bin aber weiterhin nicht sicher, ob die Berechnungen in Zeile 19 und 20 so stimmen... :(
 

vup

Mitglied
Hab es jetzt noch einmal leicht geändert:

Java:
    public static String f(final Object dObj) {
        if (dObj instanceof BigDecimal) {
            return ((BigDecimal) dObj).toPlainString();
        }
        return String.format(Locale.ROOT, "%.9f", (Double) dObj);
    }

    public static void calculate(final SimpleDateFormat sdf, final BinanceApi api, final String name) throws BinanceApiException, NoSuchFieldException, IllegalAccessException {
        //noinspection SpellCheckingInspection
        BinanceSymbol ethbtc = new BinanceSymbol("ETHBTC");
        Field symbol = ethbtc.getClass().getDeclaredField("symbol");
        symbol.setAccessible(true);
        symbol.set(ethbtc, name);
        //noinspection SpellCheckingInspection
        List<BinanceCandlestick> klines = api.klines(ethbtc, BinanceInterval.FOUR_HOURS, 31 * 6, null);
        double sumMiddle = 0;
        double sumVolatilityUp = 0;
        double sumVolatilityDown = 0;
        for (int i = 0; i < klines.size(); i++) {
            BinanceCandlestick cs = klines.get(i);
            double mid = (cs.getHigh().doubleValue() + cs.getLow().doubleValue()) / 2.0;
            double vUp = cs.getHigh().doubleValue() / mid;
            double vDown = mid / cs.getLow().doubleValue();
            sumMiddle += mid;
            sumVolatilityUp += vUp;
            sumVolatilityDown += vDown;
            System.out.println(
                    (i + 1)
                            + ";"
                            + sdf.format(new Date(cs.getOpenTime()))
                            + ";"
                            + f(cs.getHigh())
                            + ";"
                            + f(cs.getLow())
                            + ";"
                            + f(mid)
                            + ";"
                            + f(vUp)
                            + ";"
                            + f(vDown));
        }
        double avgMiddle = sumMiddle / klines.size();
        System.out.println("avgMiddle = " + f(avgMiddle));
        System.out.println("avgVolatilityUp = " + f((sumVolatilityUp / klines.size() - 1) * 100));
        System.out.println("avgVolatilityDown = " + f((sumVolatilityDown / klines.size() - 1) * 100));
    }

aber es scheint hiernach alles richtig zu sein.

Danke für eure zahlreichen Antworten. 😊
 

vup

Mitglied
Hm, glaube habe mich verzettelt. :(

Wenn die Volatility gesucht ist, meint man damit die Variance, StandardDeviation oder MeanDeviation?

Habe zudem noch diese Lib eingesetzt: https://ta4j.github.io/ta4j-wiki/Getting-started.html aber ich weiß nicht, welcher Indikator die Volatility ist:

Java:
import com.webcerebrium.binance.api.BinanceApi;
import com.webcerebrium.binance.api.BinanceApiException;
import com.webcerebrium.binance.datatype.BinanceCandlestick;
import com.webcerebrium.binance.datatype.BinanceInterval;
import com.webcerebrium.binance.datatype.BinanceSymbol;
import org.ta4j.core.BarSeries;
import org.ta4j.core.BaseBar;
import org.ta4j.core.BaseBarSeriesBuilder;
import org.ta4j.core.indicators.helpers.MedianPriceIndicator;
import org.ta4j.core.indicators.statistics.MeanDeviationIndicator;
import org.ta4j.core.indicators.statistics.StandardDeviationIndicator;
import org.ta4j.core.indicators.statistics.VarianceIndicator;
import org.ta4j.core.num.DecimalNum;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Scanner;

public class Main {
    private static final SimpleDateFormat sdf = new SimpleDateFormat();
    private static final BinanceApi api = new BinanceApi();

    public static String f(final Object dObj) {
        if (dObj instanceof BigDecimal) {
            return ((BigDecimal) dObj).toPlainString();
        }
        return String.format(Locale.ROOT, "%.9f", (Double) dObj);
    }

    public static BaseBar convertBinanceCandlestickToBaseBar(final BinanceCandlestick cs) {
        return new BaseBar(Duration.ofHours(4), ZonedDateTime.ofInstant(Instant.ofEpochMilli(cs.getOpenTime()), ZoneId.systemDefault()), DecimalNum.valueOf(cs.getOpen().doubleValue()).getDelegate(), DecimalNum.valueOf(cs.getHigh().doubleValue()).getDelegate(), DecimalNum.valueOf(cs.getLow().doubleValue()).getDelegate(), DecimalNum.valueOf(cs.getClose().doubleValue()).getDelegate(), DecimalNum.valueOf(cs.getVolume().doubleValue()).getDelegate());
    }

    public static List<BinanceCandlestick> getBinanceCandlesticks(final String name) throws BinanceApiException, Exception {
        //noinspection SpellCheckingInspection
        BinanceSymbol ethbtc = new BinanceSymbol("ETHBTC");
        Field symbol = ethbtc.getClass().getDeclaredField("symbol");
        symbol.setAccessible(true);
        symbol.set(ethbtc, name);
        return api.klines(ethbtc, BinanceInterval.FOUR_HOURS, 31 * 6, null);
    }

    public static double getAvgMiddle(final List<BinanceCandlestick> klines) {
        int n = klines.size() - 1;
        double sum = 0;
        for (int i = 0; i < n; i++) {
            BinanceCandlestick cs = klines.get(i);
            sum += (cs.getHigh().doubleValue() + cs.getLow().doubleValue()) / 2.0;
        }
        return sum / n;
    }

    public static double getAvgVolatility1(final List<BinanceCandlestick> klines) {
        int n = klines.size() - 1;
        double sumVolatility = 0;
        for (int i = 0; i < n; i++) {
            BinanceCandlestick cs = klines.get(i);
            sumVolatility += cs.getHigh().doubleValue() / cs.getLow().doubleValue();
        }
        return sumVolatility / n;
    }

    public static double[] getAvgVolatility2(final List<BinanceCandlestick> klines) {
        int n = klines.size() - 1;
        BarSeries series = new BaseBarSeriesBuilder().withName("my_series").build();
        for (int i = 0; i < n; i++) {
            BinanceCandlestick cs = klines.get(i);
            series.addBar(convertBinanceCandlestickToBaseBar(cs));
        }
        MedianPriceIndicator mpi = new MedianPriceIndicator(series);
        VarianceIndicator vi = new VarianceIndicator(mpi, n);
        StandardDeviationIndicator sdi = new StandardDeviationIndicator(mpi, n);
        MeanDeviationIndicator mdi = new MeanDeviationIndicator(mpi, n);
        return new double[]{
                vi.getValue(n - 1).doubleValue(),
                sdi.getValue(n - 1).doubleValue(),
                mdi.getValue(n - 1).doubleValue()
        };
    }

    public static void main(final String[] args) throws BinanceApiException, Exception {
        System.out.println("Enter symbol:");
        String symbol = new Scanner(System.in).nextLine();
        List<BinanceCandlestick> cs = getBinanceCandlesticks(symbol);
        double m1 = getAvgMiddle(cs);
        double v1 = getAvgVolatility1(cs);
        double[] v2 = getAvgVolatility2(cs);
        System.out.println(f(m1));
        System.out.println(f((v1 - 1) / 2 * 100));
        System.out.println(f(v2[0]));
        System.out.println(f(v2[1]));
        System.out.println(f(v2[2]));
    }
}

Für ETHBTC:

Code:
0.068554122
0.449285643
0.000005864
0.002421631
0.001936298

Wäre super, wenn hier einmal jemand von den Börsen-Füchsen antworten würde. :)
 

vup

Mitglied
Ich habe euch das, was ich haben möchte, einfach mal aufgezeichnet: ( nehmt euch in Acht vor meinen Zeichenkünsten :D )

1679604741314.png

... also jeweils die Boxhöhe, summiert und durch die Anzahl dividiert .... :s
 

Marinek

Bekanntes Mitglied
Ich versuche, die durchschnittliche Kursvolatility in Prozent mithilfe von 4-Stunden-Kerzen über einen Zeitraum von 1 Monat zu berechnen. Bin mir aber unsicher, ob der Rechenweg so richtig wäre:

Das werden wir einfach niemals erfahren.

Und viele haben dir schon öfter gesagt, dass die Informatik nicht aus einfach komplizierten Rechenwegen besteht.
 

vup

Mitglied
Wenn ein so ein Candlestick eine Box darstellt, dann wäre die Boxhöhe doch cs.getHigh() - cs.getLow(), oder sehe ich das falsch?
Das müsste so tatsächlich auch richtig sein. Gesucht ist der Abstand/Höhe ja in Prozent...

Das werden wir einfach niemals erfahren.

Und viele haben dir schon öfter gesagt, dass die Informatik nicht aus einfach komplizierten Rechenwegen besteht.
Hm, wie wäre es mal mit etwas Konstruktivem? Habe dir schließlich nichts getan... Und ich finde es auch voll schön, dass du ein iPhone hast... Was wäre die Welt schon ohne Snobs :D
 

Blender3D

Top Contributor
Bin aber weiterhin nicht sicher, ob die Berechnungen in Zeile 19 und 20 so stimmen... :(
Die stimmen mit Sicherheit nicht.

Java:
         double mid = (cs.getHigh().doubleValue() + cs.getLow().doubleValue()) / 2.0;
         double vUp = cs.getHigh().doubleValue() / mid;
         double vDown = mid / cs.getLow().doubleValue();

Der Mittelwert ist die Summer aller Werte geteilt durch die Anzahl der Werte.
Also z.B. {10,12,30 }
mid = (10+12+30)/3 = 17.333..
bei dir aber ( 30+10) /2 = 20
Die Volatilität berechnet sich dann so.

1679751752797.png
Tipp schreib dir eine Klasse die diese Berechnungen einzeln durchführt und benutze sie in deinem Code.

z.B.
Java:
    public double midPoint(double[] values) {
        double result = 0;
        for (int i = 0; i < values.length; i++)
            result += values[i];
        return result / values.length;
    }

    public double volatility(double[] values, double midPoint) {
        double result = 0;
        for (int i = 0; i < values.length; i++) {
            double val = values[i] - midPoint;
            result += val * val;
        }
        return Math.sqrt(result / values.length);
    }
 

vup

Mitglied
Blöde Frage, aber die Wurzel und die Quadrate in den Volatilitätsformeln sind doch im grunde nur syntaktischer Zucker ... abs(<...>) sollte doch langen?

Und dann hab ich doch die absolute, nicht prozentuale Volatilität... ich finde meine "Berechnung" nach wie vor nicht falsch... :confused:
 

KonradN

Super-Moderator
Mitarbeiter
Blöde Frage, aber die Wurzel und die Quadrate in den Volatilitätsformeln sind doch im grunde nur syntaktischer Zucker ... abs(<...>) sollte doch langen?

Und dann hab ich doch die absolute, nicht prozentuale Volatilität... ich finde meine "Berechnung" nach wie vor nicht falsch... :confused:
Die Frage ist doch, was Du genau haben willst. Wenn Du A willst, aber B berechnest, dann hast Du halt B und nicht A.
Die Berechnung für B wäre richtig, für A halt nicht.

Ob es eine Rolle spielt oder nicht, musst Du wissen. Aber dass es eben kein syntaktischer Zucker ist kann man ja schnell ermitteln:
Nehemn wir einfach nur zwei Abstände: 2 und 4.
Dann haben wir einmal "ohne Wurzel und Quadrate" ein einfachers (2+4) / 2 = 3
Mit der Formel zur Volatilität haben wir: sqrt( (4+16)/2 ) = sqrt(10)

Damit ist es kein syntaktischer Zucker sondern führt zu abweichenden Werten.
 

temi

Top Contributor
Ich war schon immer der Ansicht, dass beim Satz des Pythagoras die ganzen Wurzeln und Quadrate überflüssig sind. ;)

Abgesehen davon. "Syntaktischer Zucker" sind Syntaxerweiterungen zur Vereinfachung und nicht, um etwas unnötig komplizierter zu machen.
 

vup

Mitglied
Ob es eine Rolle spielt oder nicht, musst Du wissen. Aber dass es eben kein syntaktischer Zucker ist kann man ja schnell ermitteln:
Nehemn wir einfach nur zwei Abstände: 2 und 4.
Dann haben wir einmal "ohne Wurzel und Quadrate" ein einfachers (2+4) / 2 = 3
Mit der Formel zur Volatilität haben wir: sqrt( (4+16)/2 ) = sqrt(10)

Hm, wie in der Skizze gezeigt suche ich einfach die Boxhöhen... Das ist wahrscheinlich etwas anderes als die Volatilität...

Beispiel:
index = hoch, tief, mittel, abstand
t1=9,7,8, 2
t2=8,4,6, 4
t3=8,5,6.5, 3

Ich hätte einfach gerechnet:
Volatilität = (2+4+3)/3 = 3
Durchschnittspreis = (8+6+6.5)/3 = 6.83
Volatilität in Prozent = ((6.83+3/2) / (6.83-3/2) - 1)x100 = (8.33 / 5.33 - 1)x100 = 0.56285178236397748592870544090056 x 100 = 56 %

Die/eine/meine durchschnittliche Volatilität in Prozent wäre denn ~ 56 % ...
 

Ähnliche Java Themen

Neue Themen


Oben