// Path: src/test/java/au/net/woodberry/ta/toolbox/indicators/StubDataTestUtils.java
// public class StubDataTestUtils {
// 
//     private static final String SEPARATOR = ",";
//     private static final String COMMENT_LINE = "#";
//     private static final int TIMESTAMP = 0;
//     private static final int OPEN = 1;
//     private static final int HIGH = 2;
//     private static final int LOW = 3;
//     private static final int CLOSE = 4;
//     private static final int VOLUME = 5;
// 
//     private StubDataTestUtils() {}
// 
//     public static List<Tick> createTickData(String stubData) {
//         return createTickData(stubData, SEPARATOR, null, null);
//     }
//     
//     public static List<Tick> createTickData(String stubData, DateTimeFormatter dtf) {
//         return createTickData(stubData, SEPARATOR, null, dtf);
//     }
// 
//     public static List<Tick> createTickData(String stubData, String separator, Pattern header, DateTimeFormatter dtf) {
//         List<Tick> ticks = new ArrayList<>();
//         BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(StubDataTestUtils.class.getResourceAsStream(stubData)));
//         String line;
//         try {
//             while ((line = bufferedReader.readLine()) != null) {
//                 String[] data = line.split(separator);
//                 if (data == null || (header != null && header.matcher(line).matches()) || line.startsWith(COMMENT_LINE)) { // Headers, comments, no data
//                     continue;
//                 }
//                 DateTime dt = dtf != null ? DateTime.parse(data[TIMESTAMP], dtf) : DateTime.parse(data[TIMESTAMP]);
//                 Tick tick = new Tick(dt, Double.parseDouble(data[OPEN]), Double.parseDouble(data[HIGH]), Double.parseDouble(data[LOW]),
//                         Double.parseDouble(data[CLOSE]), Double.parseDouble(data[VOLUME]));
//                 ticks.add(tick);
//             }
//             bufferedReader.close();
//         } catch (IOException e) {
//             throw new RuntimeException(e);
//         }
//         return ticks;
//     }
// }
// 
// Path: src/test/java/au/net/woodberry/ta/toolbox/indicators/Assertions.java
// public static void assertDecimalEquals(TADecimal actual, String expected) {
//     if (expected != null) {
//         assertNotNull(actual);
//         assertThat(actual).isEqualTo(TADecimal.valueOf(expected));
//     } else {
//         assertNull(actual);
//     }
// }


import au.net.woodberry.ta.toolbox.indicators.StubDataTestUtils;
import eu.verdelhan.ta4j.TADecimal;
import eu.verdelhan.ta4j.TimeSeries;
import eu.verdelhan.ta4j.indicators.simple.ClosePriceIndicator;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.junit.Test;
import static au.net.woodberry.ta.toolbox.indicators.Assertions.assertDecimalEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
    public void testNullAtrIndicatorThrowsException() {
        TimeSeries data = new TimeSeries(StubDataTestUtils.createTickData("/TEST_TRADERS_ATR_STOP_LOSS_TC1.stub", DTF));
        new TradersATRStopLossIndicator(null, new ClosePriceIndicator(data), DISPLACEMENT_FACTOR);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testNullReferenceIndicatorThrowsException() {
        TimeSeries data = new TimeSeries(StubDataTestUtils.createTickData("/TEST_TRADERS_ATR_STOP_LOSS_TC1.stub", DTF));
        new TradersATRStopLossIndicator(new AverageTrueRangeIndicator(data, LOOKBACK_PERIODS), null, DISPLACEMENT_FACTOR);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testZeroDisplacementFactorThrowsException() {
        TimeSeries data = new TimeSeries(StubDataTestUtils.createTickData("/TEST_TRADERS_ATR_STOP_LOSS_TC1.stub", DTF));
        new TradersATRStopLossIndicator(new AverageTrueRangeIndicator(data, LOOKBACK_PERIODS), new ClosePriceIndicator(data), 0);
    }

    @Test
    public void testTradersAtrStopLossLessThanAtrLookBackValueIsNull() {
        TimeSeries data = new TimeSeries(StubDataTestUtils.createTickData("/TEST_TRADERS_ATR_STOP_LOSS_TC1.stub", DTF));
        TradersATRStopLossIndicator tradersAtrStopLossIndicator = new TradersATRStopLossIndicator(new AverageTrueRangeIndicator(data, LOOKBACK_PERIODS), new ClosePriceIndicator(data), DISPLACEMENT_FACTOR);
        assertNull(tradersAtrStopLossIndicator.getValue(13));
    }

    @Test
    public void testTradersAtrStopLossValueAtLookBackPosition() {
        TimeSeries data = new TimeSeries(StubDataTestUtils.createTickData("/TEST_TRADERS_ATR_STOP_LOSS_TC1.stub", DTF));
        TradersATRStopLossIndicator tradersAtrStopLossIndicator = new TradersATRStopLossIndicator(new AverageTrueRangeIndicator(data, LOOKBACK_PERIODS), new ClosePriceIndicator(data), DISPLACEMENT_FACTOR);
        TADecimal tradersAtr = tradersAtrStopLossIndicator.getValue(14);
        assertNotNull(tradersAtr);
// Path: src/test/java/au/net/woodberry/ta/toolbox/indicators/StubDataTestUtils.java
// public class StubDataTestUtils {
// 
//     private static final String SEPARATOR = ",";
//     private static final String COMMENT_LINE = "#";
//     private static final int TIMESTAMP = 0;
//     private static final int OPEN = 1;
//     private static final int HIGH = 2;
//     private static final int LOW = 3;
//     private static final int CLOSE = 4;
//     private static final int VOLUME = 5;
// 
//     private StubDataTestUtils() {}
// 
//     public static List<Tick> createTickData(String stubData) {
//         return createTickData(stubData, SEPARATOR, null, null);
//     }
//     
//     public static List<Tick> createTickData(String stubData, DateTimeFormatter dtf) {
//         return createTickData(stubData, SEPARATOR, null, dtf);
//     }
// 
//     public static List<Tick> createTickData(String stubData, String separator, Pattern header, DateTimeFormatter dtf) {
//         List<Tick> ticks = new ArrayList<>();
//         BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(StubDataTestUtils.class.getResourceAsStream(stubData)));
//         String line;
//         try {
//             while ((line = bufferedReader.readLine()) != null) {
//                 String[] data = line.split(separator);
//                 if (data == null || (header != null && header.matcher(line).matches()) || line.startsWith(COMMENT_LINE)) { // Headers, comments, no data
//                     continue;
//                 }
//                 DateTime dt = dtf != null ? DateTime.parse(data[TIMESTAMP], dtf) : DateTime.parse(data[TIMESTAMP]);
//                 Tick tick = new Tick(dt, Double.parseDouble(data[OPEN]), Double.parseDouble(data[HIGH]), Double.parseDouble(data[LOW]),
//                         Double.parseDouble(data[CLOSE]), Double.parseDouble(data[VOLUME]));
//                 ticks.add(tick);
//             }
//             bufferedReader.close();
//         } catch (IOException e) {
//             throw new RuntimeException(e);
//         }
//         return ticks;
//     }
// }
// 
// Path: src/test/java/au/net/woodberry/ta/toolbox/indicators/Assertions.java
// public static void assertDecimalEquals(TADecimal actual, String expected) {
//     if (expected != null) {
//         assertNotNull(actual);
//         assertThat(actual).isEqualTo(TADecimal.valueOf(expected));
//     } else {
//         assertNull(actual);
//     }
// }


// Path: src/test/java/au/net/woodberry/ta/toolbox/indicators/volatility/TradersATRStopLossIndicatorTest.java
import au.net.woodberry.ta.toolbox.indicators.StubDataTestUtils;
import eu.verdelhan.ta4j.TADecimal;
import eu.verdelhan.ta4j.TimeSeries;
import eu.verdelhan.ta4j.indicators.simple.ClosePriceIndicator;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.junit.Test;
import static au.net.woodberry.ta.toolbox.indicators.Assertions.assertDecimalEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

    public void testNullAtrIndicatorThrowsException() {
        TimeSeries data = new TimeSeries(StubDataTestUtils.createTickData("/TEST_TRADERS_ATR_STOP_LOSS_TC1.stub", DTF));
        new TradersATRStopLossIndicator(null, new ClosePriceIndicator(data), DISPLACEMENT_FACTOR);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testNullReferenceIndicatorThrowsException() {
        TimeSeries data = new TimeSeries(StubDataTestUtils.createTickData("/TEST_TRADERS_ATR_STOP_LOSS_TC1.stub", DTF));
        new TradersATRStopLossIndicator(new AverageTrueRangeIndicator(data, LOOKBACK_PERIODS), null, DISPLACEMENT_FACTOR);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testZeroDisplacementFactorThrowsException() {
        TimeSeries data = new TimeSeries(StubDataTestUtils.createTickData("/TEST_TRADERS_ATR_STOP_LOSS_TC1.stub", DTF));
        new TradersATRStopLossIndicator(new AverageTrueRangeIndicator(data, LOOKBACK_PERIODS), new ClosePriceIndicator(data), 0);
    }

    @Test
    public void testTradersAtrStopLossLessThanAtrLookBackValueIsNull() {
        TimeSeries data = new TimeSeries(StubDataTestUtils.createTickData("/TEST_TRADERS_ATR_STOP_LOSS_TC1.stub", DTF));
        TradersATRStopLossIndicator tradersAtrStopLossIndicator = new TradersATRStopLossIndicator(new AverageTrueRangeIndicator(data, LOOKBACK_PERIODS), new ClosePriceIndicator(data), DISPLACEMENT_FACTOR);
        assertNull(tradersAtrStopLossIndicator.getValue(13));
    }

    @Test
    public void testTradersAtrStopLossValueAtLookBackPosition() {
        TimeSeries data = new TimeSeries(StubDataTestUtils.createTickData("/TEST_TRADERS_ATR_STOP_LOSS_TC1.stub", DTF));
        TradersATRStopLossIndicator tradersAtrStopLossIndicator = new TradersATRStopLossIndicator(new AverageTrueRangeIndicator(data, LOOKBACK_PERIODS), new ClosePriceIndicator(data), DISPLACEMENT_FACTOR);
        TADecimal tradersAtr = tradersAtrStopLossIndicator.getValue(14);
        assertNotNull(tradersAtr);
        assertDecimalEquals(tradersAtr, 5742.2857);