com.fluxtion.server.lib.pnl.calculator.DerivedRateNode Maven / Gradle / Ivy
/*
* SPDX-FileCopyrightText: © 2024 Gregory Higgins
* SPDX-License-Identifier: AGPL-3.0-only
*/
package com.fluxtion.server.lib.pnl.calculator;
import com.fluxtion.runtime.annotations.OnEventHandler;
import com.fluxtion.runtime.annotations.builder.FluxtionIgnore;
import com.fluxtion.runtime.dataflow.groupby.GroupBy;
import com.fluxtion.runtime.dataflow.groupby.GroupByHashMap;
import com.fluxtion.server.lib.pnl.MidPrice;
import com.fluxtion.server.lib.pnl.MtmInstrument;
import com.fluxtion.server.lib.pnl.refdata.Instrument;
import lombok.Data;
import org.jgrapht.GraphPath;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;
import java.util.Map;
@Data
public class DerivedRateNode {
@FluxtionIgnore
private final DefaultDirectedWeightedGraph graph = new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
@FluxtionIgnore
private final GroupByHashMap derivedRates = new GroupByHashMap<>();
@FluxtionIgnore
private final BellmanFordShortestPath shortestPath = new BellmanFordShortestPath<>(graph);
private Instrument mtmInstrument = Instrument.INSTRUMENT_USD;
@OnEventHandler
public boolean updateMtmInstrument(MtmInstrument mtmInstrumentUpdate) {
boolean change = mtmInstrument != mtmInstrumentUpdate.instrument();
mtmInstrument = mtmInstrumentUpdate.instrument();
return change;
}
@OnEventHandler
public boolean midRate(MidPrice midPrice) {
Instrument dealtInstrument = midPrice.getSymbol().dealtInstrument();
Instrument contraInstrument = midPrice.getSymbol().contraInstrument();
//no self cycles allowed
if (dealtInstrument == contraInstrument | dealtInstrument == null | contraInstrument == null) {
return false;
}
double rate = midPrice.getRate();
double logRate = Math.log10(rate);
double logInverseRate = Math.log10(1 / rate);
graph.addVertex(dealtInstrument);
graph.addVertex(contraInstrument);
if (graph.containsEdge(dealtInstrument, contraInstrument)) {
graph.setEdgeWeight(dealtInstrument, contraInstrument, logRate);
graph.setEdgeWeight(contraInstrument, dealtInstrument, logInverseRate);
} else {
graph.setEdgeWeight(graph.addEdge(dealtInstrument, contraInstrument), logRate);
graph.setEdgeWeight(graph.addEdge(contraInstrument, dealtInstrument), logInverseRate);
}
return false;
}
public boolean isMtmSymbol(MidPrice midPrice) {
return midPrice.getOppositeInstrument(mtmInstrument) != null;
}
public Instrument getMtmContraInstrument(MidPrice midPrice) {
return midPrice.getOppositeInstrument(mtmInstrument);
}
public double getMtMRate(MidPrice midPrice) {
return midPrice.getRateForInstrument(mtmInstrument);
}
public GroupBy addDerived(
GroupBy rateMapGroupBy,
GroupBy positionMapGroupBy) {
Map rateMap = rateMapGroupBy.toMap();
Map positionMap = positionMapGroupBy.toMap();
derivedRates.fromMap(rateMap);
Map derivedRateMap = derivedRates.toMap();
derivedRateMap.put(mtmInstrument, 1.0);
positionMap.keySet().forEach(
i -> {
derivedRateMap.computeIfAbsent(i, positionInstrument -> {
if (graph.containsVertex(positionInstrument) & graph.containsVertex(mtmInstrument)) {
GraphPath path = shortestPath.getPath(positionInstrument, mtmInstrument);
double log10Rate = shortestPath.getPathWeight(positionInstrument, mtmInstrument);
return Double.isInfinite(log10Rate) ? Double.NaN : Math.pow(10, log10Rate);
}
return Double.NaN;
});
}
);
return derivedRates;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy