File size: 2,310 Bytes
f5cd2d3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package com.rods.backtestingstrategies.strategy;

import com.rods.backtestingstrategies.entity.Candle;
import com.rods.backtestingstrategies.entity.TradeSignal;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class SmaCrossoverStrategy implements Strategy {

    private final int shortPeriod;
    private final int longPeriod;

    public SmaCrossoverStrategy() {
        // Default values (can later be injected / configured)
        this.shortPeriod = 20;
        this.longPeriod = 50;
    }

    public SmaCrossoverStrategy(int shortPeriod, int longPeriod) {
        if (shortPeriod >= longPeriod) {
            throw new IllegalArgumentException("Short period must be less than long period");
        }
        this.shortPeriod = shortPeriod;
        this.longPeriod = longPeriod;
    }

    @Override
    public TradeSignal evaluate(List<Candle> candles, int index) {

        Candle candle = candles.get(index);

        // Not enough data to evaluate → HOLD with candle context
        if (index < longPeriod) {
            return TradeSignal.hold();
        }

        double prevShortSma = sma(candles, index - 1, shortPeriod);
        double prevLongSma = sma(candles, index - 1, longPeriod);

        double currShortSma = sma(candles, index, shortPeriod);
        double currLongSma = sma(candles, index, longPeriod);

        // Cross up → BUY
        if (prevShortSma <= prevLongSma && currShortSma > currLongSma) {
            return TradeSignal.buy(candle);
        }

        // Cross down → SELL
        if (prevShortSma >= prevLongSma && currShortSma < currLongSma) {
            return TradeSignal.sell(candle);
        }

        // No crossover → HOLD
        return TradeSignal.hold();
    }



    /**
     * Simple Moving Average at a specific index
     */
    private double sma(List<Candle> candles, int index, int period) {
        double sum = 0.0;
        for (int i = index - period + 1; i <= index; i++) {
            sum += candles.get(i).getClosePrice();
        }
        return sum / period;
    }



    @Override
    public String getName() {
        return "SMA Crossover (" + shortPeriod + ", " + longPeriod + ")";
    }


    @Override
    public StrategyType getType() {
        return StrategyType.SMA;
    }


}