Hi Leute,
ich versuche gerade eine Markovkette zu implementieren und zu Unit testen. Leider habe ich einen Fehler in der Auswertung der Markovkette und ich find ihn nicht :-( Außerdem habe ich das Gefühl, dass mein Code immernoch so unlesbar ist, dass sich das ganze nicht gut mit Unit Tests absichern lässt.
Hier mein Code:
import java.util.HashMap;
public class StochastischerGraph {
private HashMap<String, Integer> vertexs;
private HashMap<String, Integer> edges;
public StochastischerGraph() {
setVertexs(new HashMap<String, Integer>());
setEdges(new HashMap<String, Integer>());
}
public void addVertex(Integer vertex) {
String vertexStr = String.valueOf(vertex);
if(getVertexs().containsKey(vertexStr)) {
getVertexs().put(vertexStr, getVertexs().get(vertexStr) + 1);
}
else {
getVertexs().put(vertexStr, 1);
}
}
public void addVertexNum(Integer vertex, Integer vertexNum) {
String vertexStr = String.valueOf(vertex);
getVertexs().put(vertexStr, vertexNum);
}
public void addEdge(Integer from, Integer to) {
String fromTo = String.valueOf(new StochTuple<Integer, Integer>(from, to).toString());
if(getEdges().containsKey(fromTo)) {
getEdges().put(fromTo, getEdges().get(fromTo) + 1);
}
else {
getEdges().put(fromTo, 1);
}
}
public void addEdgeNum(Integer from, Integer to, Integer edgeNum) {
String fromTo = String.valueOf(new StochTuple<Integer, Integer>(from, to).toString());
getEdges().put(fromTo, edgeNum);
}
public void save(StochastischerGraph newGraph) {
vertexs = new HashMap<String, Integer>();
edges = new HashMap<String, Integer>();
for(String key: newGraph.getEdges().keySet()) {
edges.put(key, newGraph.getEdges().get(key));
}
for(String key: newGraph.getVertexs().keySet()) {
vertexs.put(key, newGraph.getVertexs().get(key));
}
}
public HashMap<String, Integer> getVertexs() {
return this.vertexs;
}
private void setVertexs(HashMap<String, Integer> vertexs) {
this.vertexs = vertexs;
}
public HashMap<String, Integer> getEdges() {
return this.edges;
}
private void setEdges(HashMap<String, Integer> edges) {
this.edges = edges;
}
}
Ich befüttere das mit Daten per train() und berechne die prognose matrix mit updateToProgGraph():
public class Analyse {
private final Logger logger = LoggerFactory.getLogger(Analyse.class);
private HashMap<String, LinkedList<Level>> symbolsLevelsWithAnalyse;
private HashMap<String, LinkedList<Candlestick>> symbolCandleMap;
private StochastischerGraph graph;
public Analyse(HashMap<String, LinkedList<Level>> symbolsLevels,
HashMap<String, LinkedList<Candlestick>> symbolCandleMap) {
logger.info("Create new Analyse Class.");
setSymbolsLevelsWithAnalyse(symbolsLevels);
setSymbolCandleMap(symbolCandleMap);
setStochastischerGraph(new StochastischerGraph());
}
private void setSymbolsLevelsWithAnalyse(HashMap<String, LinkedList<Level>> symbolsLevels) {
this.symbolsLevelsWithAnalyse = symbolsLevels;
}
public HashMap<String, LinkedList<Level>> getSymbolsLevelsWithAnalyse() {
return this.symbolsLevelsWithAnalyse;
}
public StochastischerGraph getStochastischerGraph() {
return this.graph;
}
public void setStochastischerGraph(StochastischerGraph stochastischerGraph) {
this.graph = stochastischerGraph;
}
private HashMap<String, LinkedList<Candlestick>> getSymbolCandleMap() {
return this.symbolCandleMap;
}
private void setSymbolCandleMap(HashMap<String, LinkedList<Candlestick>> symbolCandleMap) {
this.symbolCandleMap = symbolCandleMap;
}
/**
* Liesst die Wahrscheinlichkeit aus dem Prognosegraphen ab.
*
* @param istZustand
* @param zielZustand
* @return
*/
private double calcProbability(StochastischerGraph newGraph, int istZustand, int zielZustand) {
double p = 0;
for (String vertex : newGraph.getVertexs().keySet()) {
Integer vertexNum = Integer.valueOf(vertex);
StochTuple<Integer, Integer> edge = new StochTuple<Integer, Integer>(istZustand, vertexNum);
if (newGraph.getEdges().containsKey(edge.toString())
&& (vertexNum >= 0 && vertexNum >= zielZustand || vertexNum < 0 && vertexNum <= zielZustand)) {
p += newGraph.getEdges().get(edge.toString()).doubleValue()
/ newGraph.getVertexs().get(String.valueOf(istZustand)).doubleValue();
}
}
return p;
}
/**
* Trainiert den Stoachastischen Graphen anhand der Historischen Werte.
*
*/
public void train() {
for (String symbol : getSymbolCandleMap().keySet()) {
int activVertex = 0;
Candlestick activCandle = getSymbolCandleMap().get(symbol).get(0);
for (int i = 1; i < getSymbolCandleMap().get(symbol).size(); i++) {
Candlestick nextCandle = getSymbolCandleMap().get(symbol).get(i);
int nextVertex = calculateNumberOfBreaksInOneDay(symbol, activCandle, nextCandle);
if (i != getSymbolCandleMap().size() - 1) {
graph.addVertex(nextVertex);
}
graph.addEdge(activVertex, nextVertex);
activCandle = nextCandle;
activVertex = nextVertex;
}
}
}
/**
* Aendert den Stochastischen Graph zu einem Graph dessen Kanten 30 Tage
* repraesentieren.
*
* @param tage
* @return
*/
public StochastischerGraph updateToProgGraph(int tage) {
StochastischerGraph newGraph = new StochastischerGraph();
newGraph.save(graph);
for (int i = 0; i < tage; i++) {
StochastischerGraph helperGraph = new StochastischerGraph();
for (String rootVertex : newGraph.getVertexs().keySet()) {
int activVertex = Integer.valueOf(rootVertex);
for (String vertex : newGraph.getVertexs().keySet()) {
StochTuple<Integer, Integer> edge = new StochTuple<Integer, Integer>(activVertex, Integer.valueOf(vertex));
if (newGraph.getEdges().containsKey(edge.toString())) {
for (String nextVertex : graph.getVertexs().keySet()) {
StochTuple<Integer, Integer> nextEdge = new StochTuple<Integer, Integer>(Integer.valueOf(vertex), Integer.valueOf(nextVertex));
if (graph.getEdges().containsKey(nextEdge.toString())) {
String fromTo = String.valueOf(new StochTuple<Integer, Integer>(activVertex, Integer.valueOf(nextVertex)).toString());
if(helperGraph.getEdges().containsKey(fromTo)) {
// addieren, wenn active -> vertex -> next fuer 2 unterschiedliche vertex gilt
Integer newVertexNum = helperGraph.getVertexs().get(String.valueOf(activVertex)) * newGraph.getVertexs().get(String.valueOf(activVertex)) * graph.getVertexs().get(vertex);
Integer newEdgeNum = (helperGraph.getVertexs().get(String.valueOf(activVertex)) * newGraph.getEdges().get(edge.toString()) * graph.getEdges().get(nextEdge.toString())) + (helperGraph.getEdges().get(fromTo) * newGraph.getVertexs().get(String.valueOf(activVertex)) * graph.getVertexs().get(vertex));
helperGraph.addVertexNum(activVertex, newVertexNum);
helperGraph.addEdgeNum(activVertex, Integer.valueOf(nextVertex), newEdgeNum);
}
else {
helperGraph.addVertexNum(activVertex, newGraph.getVertexs().get(String.valueOf(activVertex)) * graph.getVertexs().get(vertex));
helperGraph.addEdgeNum(activVertex, Integer.valueOf(nextVertex), newGraph.getEdges().get(edge.toString()) * graph.getEdges().get(nextEdge.toString()));
}
}
}
}
}
}
newGraph.save(helperGraph);
}
return newGraph;
}
/**
* Generiert die Wahrscheinlichkeit fuer einen durchbrochenen Widerstand
* nach 30 Tagen.
*
* @param tage
*/
public void generateProbability(int tage) {
StochastischerGraph newGraph = updateToProgGraph(tage);
for (String symbol : getSymbolsLevelsWithAnalyse().keySet()) {
Candlestick activCandle = getSymbolCandleMap().get(symbol).get(0);
for (Level level : getSymbolsLevelsWithAnalyse().get(symbol)) {
int anzahlAnNotwendigenBreaks = numberOfBreaks(activCandle, level, symbol);
double probability = calcProbability(newGraph, 0, anzahlAnNotwendigenBreaks);
level.setBreakProbability(probability);
}
}
}
}
Und hiermit Versuch ich das zu Unit Testen:
@RunWith(SpringRunner.class)
@SpringBootTest
public class AnalyseTests {
private final Logger logger = LoggerFactory.getLogger(AnalyseTests.class);
private Analyse analyse;
private LinkedList<Candlestick> candles;
private LinkedList<Level> levels;
@Before
public void setUp() {
HashMap<String, LinkedList<Candlestick>> symbolCandleMap = new HashMap<String, LinkedList<Candlestick>>();
candles = new LinkedList<Candlestick>();
candles.addLast(new Candlestick("symbol1", 3, 1, 2, 3, Timeframe.M15, new Date(1)));
candles.addLast(new Candlestick("symbol1", 5, 1, 2, 5, Timeframe.M15, new Date(2)));
candles.addLast(new Candlestick("symbol1", 3, 2, 2, 3, Timeframe.M15, new Date(3)));
candles.addLast(new Candlestick("symbol1", 4, 1, 2, 4, Timeframe.M15, new Date(4)));
candles.addLast(new Candlestick("symbol1", 3, 1, 2, 3, Timeframe.M15, new Date(5)));
candles.addLast(new Candlestick("symbol1", 3, 1, 2, 3, Timeframe.M15, new Date(6)));
candles.addLast(new Candlestick("symbol1", 1, 1, 2, 1, Timeframe.M15, new Date(7)));
candles.addLast(new Candlestick("symbol1", 2, 1, 2, 2, Timeframe.M15, new Date(8)));
candles.addLast(new Candlestick("symbol1", 2, 1, 2, 2, Timeframe.M15, new Date(9)));
HashMap<String, LinkedList<Level>> symbolsLevels = new HashMap<String, LinkedList<Level>>();
levels = new LinkedList<Level>();
levels.addLast(new Level(candles.get(1).getHigh(), candles.get(1).getLow(), LevelArt.Higher, candles.get(1).getDate()));
levels.addLast(new Level(candles.get(2).getHigh(), candles.get(2).getLow(), LevelArt.Lower, candles.get(2).getDate()));
levels.addLast(new Level(candles.get(3).getHigh(), candles.get(3).getLow(), LevelArt.Higher, candles.get(3).getDate()));
levels.addLast(new Level(candles.get(6).getHigh(), candles.get(6).getLow(), LevelArt.Lower, candles.get(6).getDate()));
symbolsLevels.put("symbol1", levels);
symbolCandleMap.put("symbol1", candles);
analyse = new Analyse(symbolsLevels, symbolCandleMap);
}
@Test
public void trainTest() {
logger.info("Start AnalyseTests: trainTest.");
analyse.train();
StochastischerGraph graph = analyse.getStochastischerGraph();
Assert.assertTrue(graph.getEdges().keySet().size() == 3);
Assert.assertTrue(graph.getVertexs().keySet().size() == 2);
analyse.setStochastischerGraph(new StochastischerGraph());
logger.info("End AnalyseTests: trainTest.");
}
@Test
public void updateToProgGraphTest() {
logger.info("Start AnalyseTests: updateToProgGraphTest.");
analyse.train();
int tage = 2;
StochastischerGraph newGraph = analyse.updateToProgGraph(tage);
// check
analyse.setStochastischerGraph(new StochastischerGraph());
logger.info("End ANalyseTests: updateToProgGraphTest.");
}
@Test
public void generateProbabilityTest() {
logger.info("Start AnalyseTests: generateProbabilityTest.");
analyse.train();
int tage = 2;
StochastischerGraph newGraph = analyse.updateToProgGraph(tage);
// check
analyse.setStochastischerGraph(new StochastischerGraph());
logger.info("End AnalyseTests: generateProbabilityTest.");
}
}
Leider habe ich einen Fehler in updateToProgGraph. Der Gedanke einer Markovkette ist, dass wir einen Graphen bzw eine Matrix P mit Häufigkeiten haben mit der Aussage: Heute stehen wir auf Zustand x und haben historisch folgende häufigkeit zu zustand y zu wechseln. In updateToPrgGraph rechnen wir das für n-Tage hoch indem wir P^n rechnen (wir berechnen damit die häufigkeit das wir in exakt n-Tage aufzustand y landen).
Ich habe folgende 2 Probleme:
- Ich finde den Fehler nicht
- Ich krieg die scheiße nicht gut geunittestet, weil mein Code nicht gut testbar ist.
Habt ihr ein paar verbesserungsvorschläge? besonders zu code testbarkeit?