goldenChat base source add
This commit is contained in:
+461
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
package ta4jexamples.indicators;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.ta4j.core.Bar;
|
||||
import org.ta4j.core.BarBuilder;
|
||||
import org.ta4j.core.BarSeries;
|
||||
import org.ta4j.core.BaseBarSeriesBuilder;
|
||||
import org.ta4j.core.Indicator;
|
||||
import org.ta4j.core.indicators.CachedIndicator;
|
||||
import org.ta4j.core.indicators.averages.SMAIndicator;
|
||||
import org.ta4j.core.indicators.helpers.ClosePriceIndicator;
|
||||
import org.ta4j.core.num.DoubleNumFactory;
|
||||
import org.ta4j.core.num.Num;
|
||||
import org.ta4j.core.num.NumFactory;
|
||||
|
||||
/**
|
||||
* Benchmark focused on the performance characteristics of
|
||||
* {@link CachedIndicator}.
|
||||
*
|
||||
* <p>
|
||||
* This is intended for before/after comparisons across branches: run this
|
||||
* benchmark on the feature branch, then checkout {@code master} and run it
|
||||
* again.
|
||||
*
|
||||
* <p>
|
||||
* Scenarios:
|
||||
* <ul>
|
||||
* <li>Bounded cache eviction (hot path for streaming/rolling windows)</li>
|
||||
* <li>Concurrent cache-hit reads (contention on read-mostly workloads)</li>
|
||||
* <li>Repeated reads of the last bar (common in live feeds where the last bar
|
||||
* is queried frequently)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 0.22.0
|
||||
*/
|
||||
public class CachedIndicatorBenchmark {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(CachedIndicatorBenchmark.class);
|
||||
|
||||
private static final int DEFAULT_THREADS = Math.max(8, Runtime.getRuntime().availableProcessors());
|
||||
private static final int DEFAULT_BATCHES = 3;
|
||||
|
||||
private static final int DEFAULT_EVICTION_BAR_COUNT = 200_000;
|
||||
private static final int DEFAULT_MAXIMUM_BAR_COUNT_HINT = 512;
|
||||
|
||||
private static final int DEFAULT_CACHE_HIT_READS_PER_THREAD = 1_000_000;
|
||||
private static final int DEFAULT_LAST_BAR_READS = 1_000_000;
|
||||
private static final int DEFAULT_LAST_BAR_SMA_PERIOD = 50;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
int threads = args.length > 0 ? Integer.parseInt(args[0]) : DEFAULT_THREADS;
|
||||
int batches = args.length > 1 ? Integer.parseInt(args[1]) : DEFAULT_BATCHES;
|
||||
int evictionBars = args.length > 2 ? Integer.parseInt(args[2]) : DEFAULT_EVICTION_BAR_COUNT;
|
||||
int cacheHitsPerThread = args.length > 3 ? Integer.parseInt(args[3]) : DEFAULT_CACHE_HIT_READS_PER_THREAD;
|
||||
int lastBarReads = args.length > 4 ? Integer.parseInt(args[4]) : DEFAULT_LAST_BAR_READS;
|
||||
int maximumBarCountHint = args.length > 5 ? Integer.parseInt(args[5]) : DEFAULT_MAXIMUM_BAR_COUNT_HINT;
|
||||
int lastBarSmaPeriod = args.length > 6 ? Integer.parseInt(args[6]) : DEFAULT_LAST_BAR_SMA_PERIOD;
|
||||
|
||||
new CachedIndicatorBenchmark().run(threads, batches, evictionBars, cacheHitsPerThread, lastBarReads,
|
||||
maximumBarCountHint, lastBarSmaPeriod);
|
||||
}
|
||||
|
||||
ScenarioResult runBoundedEvictionScenario(int barCount, int maximumBarCountHint) {
|
||||
BarSeries series = buildSeries(barCount);
|
||||
return benchmarkBoundedEviction(series, maximumBarCountHint);
|
||||
}
|
||||
|
||||
ScenarioResult runConcurrentCacheHitsScenario(int barCount, int threads, int readsPerThread) {
|
||||
BarSeries series = buildSeries(barCount);
|
||||
return benchmarkConcurrentCacheHits(series, threads, readsPerThread);
|
||||
}
|
||||
|
||||
ScenarioResult runLastBarHotReadsScenario(int barCount, int smaPeriod, int reads) {
|
||||
BarSeries series = buildSeries(barCount);
|
||||
return benchmarkLastBarHotReads(series, smaPeriod, reads);
|
||||
}
|
||||
|
||||
private void run(int threads, int batches, int evictionBars, int cacheHitsPerThread, int lastBarReads,
|
||||
int maximumBarCountHint, int lastBarSmaPeriod) throws Exception {
|
||||
LOG.info(
|
||||
"Starting CachedIndicator benchmark: threads={}, batches={}, evictionBars={}, cacheHitsPerThread={}, lastBarReads={}, maxBarCountHint={}, lastBarSmaPeriod={}",
|
||||
threads, batches, formatLong(evictionBars), formatLong(cacheHitsPerThread), formatLong(lastBarReads),
|
||||
formatLong(maximumBarCountHint), formatLong(lastBarSmaPeriod));
|
||||
|
||||
var evictionSeries = buildSeries(evictionBars);
|
||||
var cacheHitSeries = buildSeries(Math.max(5_000, lastBarSmaPeriod + 2));
|
||||
var lastBarSeries = buildSeries(Math.max(5_000, lastBarSmaPeriod + 2));
|
||||
|
||||
Map<String, ScenarioStats> statsByScenario = new HashMap<>();
|
||||
for (int batch = 1; batch <= batches; batch++) {
|
||||
runScenario("Bounded eviction (monotonic indices)", batch, statsByScenario,
|
||||
() -> benchmarkBoundedEviction(evictionSeries, maximumBarCountHint));
|
||||
runScenario("Concurrent cache hits (same index)", batch, statsByScenario,
|
||||
() -> benchmarkConcurrentCacheHits(cacheHitSeries, threads, cacheHitsPerThread));
|
||||
runScenario("Last bar hot reads (SMA)", batch, statsByScenario,
|
||||
() -> benchmarkLastBarHotReads(lastBarSeries, lastBarSmaPeriod, lastBarReads));
|
||||
}
|
||||
|
||||
logSummary(statsByScenario);
|
||||
}
|
||||
|
||||
private void runScenario(String name, int batch, Map<String, ScenarioStats> statsByScenario,
|
||||
Supplier<ScenarioResult> runner) throws Exception {
|
||||
LOG.info("Batch {}: {}", batch, name);
|
||||
|
||||
ScenarioResult result = runner.get();
|
||||
ScenarioStats stats = statsByScenario.computeIfAbsent(name, ignored -> new ScenarioStats());
|
||||
stats.add(result);
|
||||
|
||||
LOG.info(" duration={} ms, ops={}, throughput={} ops/s, checksum={}", formatMillis(result.durationNanos),
|
||||
formatLong(result.operations), formatDouble(result.throughputOpsPerSecond), result.checksum);
|
||||
}
|
||||
|
||||
private void logSummary(Map<String, ScenarioStats> statsByScenario) {
|
||||
LOG.info("CachedIndicator benchmark summary (averages across batches):");
|
||||
for (Map.Entry<String, ScenarioStats> entry : statsByScenario.entrySet()) {
|
||||
ScenarioStats stats = entry.getValue();
|
||||
LOG.info(" {}: avgDuration={} ms, avgThroughput={} ops/s (runs={})", entry.getKey(),
|
||||
formatMillis(stats.averageDurationNanos()), formatDouble(stats.averageThroughputOpsPerSecond()),
|
||||
stats.runs);
|
||||
}
|
||||
}
|
||||
|
||||
private ScenarioResult benchmarkBoundedEviction(BarSeries baseSeries, int maximumBarCountHint) {
|
||||
BarSeries series = new MaxBarCountHintSeries(baseSeries, maximumBarCountHint);
|
||||
Indicator<Integer> indicator = new IndexIndicator(series);
|
||||
int endIndex = series.getEndIndex();
|
||||
|
||||
// Warm-up the cache machinery a bit (avoid timing the "first use" path).
|
||||
for (int i = 0; i < Math.min(endIndex, maximumBarCountHint + 16); i++) {
|
||||
indicator.getValue(i);
|
||||
}
|
||||
|
||||
long checksum = 0;
|
||||
int operations = Math.max(0, endIndex);
|
||||
|
||||
long startNanos = System.nanoTime();
|
||||
for (int i = 0; i < endIndex; i++) {
|
||||
checksum += indicator.getValue(i);
|
||||
}
|
||||
long durationNanos = System.nanoTime() - startNanos;
|
||||
|
||||
requireTrue(endIndex >= 1, "Series must contain at least one bar");
|
||||
requireEquals(Integer.valueOf(endIndex - 1), indicator.getValue(endIndex - 1), "Index indicator mismatch");
|
||||
|
||||
return new ScenarioResult(operations, durationNanos, checksum);
|
||||
}
|
||||
|
||||
private ScenarioResult benchmarkConcurrentCacheHits(BarSeries baseSeries, int threads, int readsPerThread) {
|
||||
BarSeries series = new MaxBarCountHintSeries(baseSeries, Integer.MAX_VALUE);
|
||||
Indicator<Integer> indicator = new IndexIndicator(series);
|
||||
int hitIndex = Math.max(0, series.getEndIndex() - 1);
|
||||
indicator.getValue(hitIndex);
|
||||
|
||||
ExecutorService pool = Executors.newFixedThreadPool(threads);
|
||||
try {
|
||||
CountDownLatch ready = new CountDownLatch(threads);
|
||||
CountDownLatch start = new CountDownLatch(1);
|
||||
CountDownLatch done = new CountDownLatch(threads);
|
||||
|
||||
List<CompletableFuture<Long>> futures = new ArrayList<>(threads);
|
||||
for (int i = 0; i < threads; i++) {
|
||||
futures.add(CompletableFuture.supplyAsync(() -> {
|
||||
ready.countDown();
|
||||
try {
|
||||
start.await();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return 0L;
|
||||
}
|
||||
long localChecksum = 0;
|
||||
for (int j = 0; j < readsPerThread; j++) {
|
||||
localChecksum += indicator.getValue(hitIndex);
|
||||
}
|
||||
done.countDown();
|
||||
return localChecksum;
|
||||
}, pool));
|
||||
}
|
||||
|
||||
awaitLatch(ready, Duration.ofSeconds(30), "workers to become ready");
|
||||
|
||||
long startNanos = System.nanoTime();
|
||||
start.countDown();
|
||||
awaitLatch(done, Duration.ofMinutes(2), "workers to finish");
|
||||
long durationNanos = System.nanoTime() - startNanos;
|
||||
|
||||
long checksum = 0;
|
||||
for (CompletableFuture<Long> future : futures) {
|
||||
checksum += future.join();
|
||||
}
|
||||
|
||||
long operations = (long) threads * readsPerThread;
|
||||
return new ScenarioResult(operations, durationNanos, checksum);
|
||||
} finally {
|
||||
pool.shutdown();
|
||||
try {
|
||||
pool.awaitTermination(30, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ScenarioResult benchmarkLastBarHotReads(BarSeries baseSeries, int smaPeriod, int reads) {
|
||||
BarSeries series = new MaxBarCountHintSeries(baseSeries, Integer.MAX_VALUE);
|
||||
ClosePriceIndicator closePrice = new ClosePriceIndicator(series);
|
||||
SMAIndicator sma = new SMAIndicator(closePrice, smaPeriod);
|
||||
|
||||
int endIndex = series.getEndIndex();
|
||||
|
||||
// Warm up: compute once so cache-hit behavior is measured.
|
||||
Num expected = sma.getValue(endIndex);
|
||||
|
||||
long checksum = 0;
|
||||
long startNanos = System.nanoTime();
|
||||
for (int i = 0; i < reads; i++) {
|
||||
Num value = sma.getValue(endIndex);
|
||||
checksum += value.hashCode();
|
||||
}
|
||||
long durationNanos = System.nanoTime() - startNanos;
|
||||
|
||||
requireEquals(expected, sma.getValue(endIndex), "Last bar SMA must remain stable across reads");
|
||||
|
||||
return new ScenarioResult(reads, durationNanos, checksum);
|
||||
}
|
||||
|
||||
static BarSeries buildSeries(int barCount) {
|
||||
var numFactory = DoubleNumFactory.getInstance();
|
||||
BarSeries series = new BaseBarSeriesBuilder().withNumFactory(numFactory).build();
|
||||
|
||||
Duration timePeriod = Duration.ofDays(1);
|
||||
Instant endTime = Instant.EPOCH;
|
||||
for (int i = 0; i < barCount; i++) {
|
||||
endTime = endTime.plus(timePeriod);
|
||||
series.barBuilder()
|
||||
.timePeriod(timePeriod)
|
||||
.endTime(endTime)
|
||||
.closePrice(i + 1d)
|
||||
.openPrice(i + 1d)
|
||||
.highPrice(i + 1d)
|
||||
.lowPrice(i + 1d)
|
||||
.volume(1d)
|
||||
.add();
|
||||
}
|
||||
return series;
|
||||
}
|
||||
|
||||
private static void awaitLatch(CountDownLatch latch, Duration timeout, String what) {
|
||||
try {
|
||||
boolean completed = latch.await(timeout.toMillis(), TimeUnit.MILLISECONDS);
|
||||
requireTrue(completed, "Timed out waiting for " + what);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IllegalStateException("Interrupted while waiting for " + what, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void requireTrue(boolean condition, String message) {
|
||||
if (!condition) {
|
||||
throw new IllegalStateException(message);
|
||||
}
|
||||
}
|
||||
|
||||
private static void requireEquals(Object expected, Object actual, String message) {
|
||||
if (!Objects.equals(expected, actual)) {
|
||||
throw new IllegalStateException(message + " (expected=" + expected + ", actual=" + actual + ')');
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatLong(long value) {
|
||||
return NumberFormat.getNumberInstance(Locale.US).format(value);
|
||||
}
|
||||
|
||||
private static String formatMillis(double nanos) {
|
||||
double millis = nanos / 1_000_000d;
|
||||
return NumberFormat.getNumberInstance(Locale.US).format(millis);
|
||||
}
|
||||
|
||||
private static String formatDouble(double value) {
|
||||
NumberFormat format = NumberFormat.getNumberInstance(Locale.US);
|
||||
format.setMaximumFractionDigits(2);
|
||||
return format.format(value);
|
||||
}
|
||||
|
||||
static final class ScenarioResult {
|
||||
|
||||
private final long operations;
|
||||
private final long durationNanos;
|
||||
private final long checksum;
|
||||
private final double throughputOpsPerSecond;
|
||||
|
||||
ScenarioResult(long operations, long durationNanos, long checksum) {
|
||||
this.operations = operations;
|
||||
this.durationNanos = durationNanos;
|
||||
this.checksum = checksum;
|
||||
this.throughputOpsPerSecond = operations / (durationNanos / 1_000_000_000d);
|
||||
}
|
||||
|
||||
long getOperations() {
|
||||
return operations;
|
||||
}
|
||||
|
||||
long getDurationNanos() {
|
||||
return durationNanos;
|
||||
}
|
||||
|
||||
long getChecksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
double getThroughputOpsPerSecond() {
|
||||
return throughputOpsPerSecond;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ScenarioStats {
|
||||
|
||||
private int runs;
|
||||
private double totalDurationNanos;
|
||||
private double totalThroughputOpsPerSecond;
|
||||
|
||||
private void add(ScenarioResult result) {
|
||||
runs++;
|
||||
totalDurationNanos += result.durationNanos;
|
||||
totalThroughputOpsPerSecond += result.throughputOpsPerSecond;
|
||||
}
|
||||
|
||||
private double averageDurationNanos() {
|
||||
return totalDurationNanos / runs;
|
||||
}
|
||||
|
||||
private double averageThroughputOpsPerSecond() {
|
||||
return totalThroughputOpsPerSecond / runs;
|
||||
}
|
||||
}
|
||||
|
||||
static final class IndexIndicator extends CachedIndicator<Integer> {
|
||||
|
||||
private IndexIndicator(BarSeries series) {
|
||||
super(series);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer calculate(int index) {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCountOfUnstableBars() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static final class MaxBarCountHintSeries implements BarSeries {
|
||||
|
||||
private static final long serialVersionUID = 3793483697719901088L;
|
||||
|
||||
private final BarSeries delegate;
|
||||
private final int maximumBarCountHint;
|
||||
|
||||
private MaxBarCountHintSeries(BarSeries delegate, int maximumBarCountHint) {
|
||||
this.delegate = delegate;
|
||||
this.maximumBarCountHint = maximumBarCountHint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumFactory numFactory() {
|
||||
return delegate.numFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BarBuilder barBuilder() {
|
||||
return delegate.barBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return delegate.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bar getBar(int i) {
|
||||
return delegate.getBar(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBarCount() {
|
||||
return delegate.getBarCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Bar> getBarData() {
|
||||
return delegate.getBarData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBeginIndex() {
|
||||
return delegate.getBeginIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEndIndex() {
|
||||
return delegate.getEndIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaximumBarCount() {
|
||||
return maximumBarCountHint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaximumBarCount(int maximumBarCount) {
|
||||
throw new UnsupportedOperationException("Maximum bar count is a hint-only override for benchmarking");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRemovedBarsCount() {
|
||||
return delegate.getRemovedBarsCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBar(Bar bar, boolean replace) {
|
||||
delegate.addBar(bar, replace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTrade(Num tradeVolume, Num tradePrice) {
|
||||
delegate.addTrade(tradeVolume, tradePrice);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPrice(Num price) {
|
||||
delegate.addPrice(price);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BarSeries getSubSeries(int startIndex, int endIndex) {
|
||||
return delegate.getSubSeries(startIndex, endIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
package ta4jexamples.indicators;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.util.Date;
|
||||
|
||||
import org.jfree.chart.ChartFactory;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.plot.DatasetRenderingOrder;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.xy.CandlestickRenderer;
|
||||
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||
import org.jfree.chart.ui.ApplicationFrame;
|
||||
import org.jfree.chart.ui.UIUtils;
|
||||
import org.jfree.data.time.Second;
|
||||
import org.jfree.data.time.TimeSeries;
|
||||
import org.jfree.data.time.TimeSeriesCollection;
|
||||
import org.jfree.data.xy.DefaultHighLowDataset;
|
||||
import org.jfree.data.xy.OHLCDataset;
|
||||
import org.ta4j.core.Bar;
|
||||
import org.ta4j.core.BarSeries;
|
||||
import org.ta4j.core.indicators.helpers.ClosePriceIndicator;
|
||||
|
||||
import ta4jexamples.datasources.BitStampCsvTradesFileBarSeriesDataSource;
|
||||
|
||||
/**
|
||||
* This class builds a traditional candlestick chart.
|
||||
*/
|
||||
public class CandlestickChart {
|
||||
|
||||
/**
|
||||
* Builds a JFreeChart OHLC dataset from a ta4j bar series.
|
||||
*
|
||||
* @param series the bar series
|
||||
* @return an Open-High-Low-Close dataset
|
||||
*/
|
||||
private static OHLCDataset createOHLCDataset(BarSeries series) {
|
||||
final int nbBars = series.getBarCount();
|
||||
|
||||
Date[] dates = new Date[nbBars];
|
||||
double[] opens = new double[nbBars];
|
||||
double[] highs = new double[nbBars];
|
||||
double[] lows = new double[nbBars];
|
||||
double[] closes = new double[nbBars];
|
||||
double[] volumes = new double[nbBars];
|
||||
|
||||
for (int i = 0; i < nbBars; i++) {
|
||||
Bar bar = series.getBar(i);
|
||||
dates[i] = new Date(bar.getEndTime().toEpochMilli());
|
||||
opens[i] = bar.getOpenPrice().doubleValue();
|
||||
highs[i] = bar.getHighPrice().doubleValue();
|
||||
lows[i] = bar.getLowPrice().doubleValue();
|
||||
closes[i] = bar.getClosePrice().doubleValue();
|
||||
volumes[i] = bar.getVolume().doubleValue();
|
||||
}
|
||||
|
||||
return new DefaultHighLowDataset("btc", dates, highs, lows, opens, closes, volumes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an additional JFreeChart dataset from a ta4j bar series.
|
||||
*
|
||||
* @param series the bar series
|
||||
* @return an additional dataset
|
||||
*/
|
||||
private static TimeSeriesCollection createAdditionalDataset(BarSeries series) {
|
||||
ClosePriceIndicator indicator = new ClosePriceIndicator(series);
|
||||
TimeSeriesCollection dataset = new TimeSeriesCollection();
|
||||
TimeSeries chartTimeSeries = new TimeSeries("Btc price");
|
||||
for (int i = 0; i < series.getBarCount(); i++) {
|
||||
Bar bar = series.getBar(i);
|
||||
chartTimeSeries.add(new Second(new Date(bar.getEndTime().toEpochMilli())),
|
||||
indicator.getValue(i).doubleValue());
|
||||
}
|
||||
dataset.addSeries(chartTimeSeries);
|
||||
return dataset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a chart in a frame. The frame is configured to avoid stealing focus
|
||||
* when launched from tests or scripts.
|
||||
*
|
||||
* @param chart the chart to be displayed
|
||||
*/
|
||||
private static void displayChart(JFreeChart chart) {
|
||||
// Chart panel
|
||||
ChartPanel panel = new ChartPanel(chart);
|
||||
panel.setFillZoomRectangle(true);
|
||||
panel.setMouseWheelEnabled(true);
|
||||
panel.setPreferredSize(new Dimension(740, 300));
|
||||
// Application frame
|
||||
ApplicationFrame frame = new ApplicationFrame("Ta4j example - Candlestick chart");
|
||||
frame.setContentPane(panel);
|
||||
frame.pack();
|
||||
UIUtils.centerFrameOnScreen(frame);
|
||||
frame.setFocusableWindowState(false);
|
||||
frame.setVisible(true);
|
||||
frame.setAlwaysOnTop(false);
|
||||
frame.setAutoRequestFocus(false);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
/*
|
||||
* Getting bar series
|
||||
*/
|
||||
BarSeries series = BitStampCsvTradesFileBarSeriesDataSource.loadBitstampSeries();
|
||||
|
||||
/*
|
||||
* Creating the OHLC dataset
|
||||
*/
|
||||
OHLCDataset ohlcDataset = createOHLCDataset(series);
|
||||
|
||||
/*
|
||||
* Creating the additional dataset
|
||||
*/
|
||||
TimeSeriesCollection xyDataset = createAdditionalDataset(series);
|
||||
|
||||
/*
|
||||
* Creating the chart
|
||||
*/
|
||||
JFreeChart chart = ChartFactory.createCandlestickChart("Bitstamp BTC price", "Time", "USD", ohlcDataset, true);
|
||||
// Candlestick rendering
|
||||
CandlestickRenderer renderer = new CandlestickRenderer();
|
||||
renderer.setAutoWidthMethod(CandlestickRenderer.WIDTHMETHOD_SMALLEST);
|
||||
XYPlot plot = chart.getXYPlot();
|
||||
plot.setRenderer(renderer);
|
||||
// Additional dataset
|
||||
int index = 1;
|
||||
plot.setDataset(index, xyDataset);
|
||||
plot.mapDatasetToRangeAxis(index, 0);
|
||||
XYLineAndShapeRenderer renderer2 = new XYLineAndShapeRenderer(true, false);
|
||||
renderer2.setSeriesPaint(index, Color.blue);
|
||||
plot.setRenderer(index, renderer2);
|
||||
// Misc
|
||||
plot.setRangeGridlinePaint(Color.lightGray);
|
||||
plot.setBackgroundPaint(Color.white);
|
||||
NumberAxis numberAxis = (NumberAxis) plot.getRangeAxis();
|
||||
numberAxis.setAutoRangeIncludesZero(false);
|
||||
plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
|
||||
|
||||
/*
|
||||
* Displaying the chart
|
||||
*/
|
||||
displayChart(chart);
|
||||
}
|
||||
}
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
package ta4jexamples.indicators;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.Stroke;
|
||||
import java.util.Date;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.annotations.XYLineAnnotation;
|
||||
import org.jfree.chart.axis.DateAxis;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.plot.CombinedDomainXYPlot;
|
||||
import org.jfree.chart.plot.DatasetRenderingOrder;
|
||||
import org.jfree.chart.plot.PlotOrientation;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.xy.CandlestickRenderer;
|
||||
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||
import org.jfree.chart.ui.ApplicationFrame;
|
||||
import org.jfree.chart.ui.UIUtils;
|
||||
import org.jfree.data.time.Second;
|
||||
import org.jfree.data.time.TimeSeries;
|
||||
import org.jfree.data.time.TimeSeriesCollection;
|
||||
import org.jfree.data.xy.DefaultHighLowDataset;
|
||||
import org.jfree.data.xy.OHLCDataset;
|
||||
import org.jfree.data.xy.XYDataset;
|
||||
import org.ta4j.core.Bar;
|
||||
import org.ta4j.core.BarSeries;
|
||||
import org.ta4j.core.indicators.ChopIndicator;
|
||||
import org.ta4j.core.indicators.helpers.ClosePriceIndicator;
|
||||
|
||||
import ta4jexamples.datasources.BitStampCsvTradesFileBarSeriesDataSource;
|
||||
|
||||
/**
|
||||
* This class builds a traditional candlestick chart.
|
||||
*/
|
||||
public class CandlestickChartWithChopIndicator {
|
||||
private static final int CHOP_INDICATOR_TIMEFRAME = 14;
|
||||
private static final double CHOP_UPPER_THRESHOLD = 61.8;
|
||||
private static final double CHOP_LOWER_THRESHOLD = 38.2;
|
||||
private static final int VOLUME_DATASET_INDEX = 1;
|
||||
private static final int CHOP_SCALE_VALUE = 100;
|
||||
private static CombinedDomainXYPlot combinedPlot;
|
||||
private static JFreeChart combinedChart;
|
||||
static DateAxis xAxis = new DateAxis("Time");
|
||||
private static ChartPanel combinedChartPanel;
|
||||
private static XYPlot indicatorXYPlot;
|
||||
static Stroke dashedThinLineStyle = new BasicStroke(0.4f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f,
|
||||
new float[] { 8.0f, 4.0f }, 0.0f);
|
||||
static BarSeries series;
|
||||
|
||||
/**
|
||||
* Builds a JFreeChart OHLC dataset from a ta4j bar series.
|
||||
*
|
||||
* @param series a bar series
|
||||
* @return an Open-High-Low-Close dataset
|
||||
*/
|
||||
private static OHLCDataset createOHLCDataset(BarSeries series) {
|
||||
final int nbBars = series.getBarCount();
|
||||
|
||||
Date[] dates = new Date[nbBars];
|
||||
double[] opens = new double[nbBars];
|
||||
double[] highs = new double[nbBars];
|
||||
double[] lows = new double[nbBars];
|
||||
double[] closes = new double[nbBars];
|
||||
double[] volumes = new double[nbBars];
|
||||
|
||||
for (int i = 0; i < nbBars; i++) {
|
||||
Bar bar = series.getBar(i);
|
||||
dates[i] = new Date(bar.getEndTime().toEpochMilli());
|
||||
opens[i] = bar.getOpenPrice().doubleValue();
|
||||
highs[i] = bar.getHighPrice().doubleValue();
|
||||
lows[i] = bar.getLowPrice().doubleValue();
|
||||
closes[i] = bar.getClosePrice().doubleValue();
|
||||
volumes[i] = bar.getVolume().doubleValue();
|
||||
}
|
||||
|
||||
return new DefaultHighLowDataset("btc", dates, highs, lows, opens, closes, volumes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an additional JFreeChart dataset from a ta4j bar series.
|
||||
*
|
||||
* @param series a bar series
|
||||
* @return an additional dataset
|
||||
*/
|
||||
private static TimeSeriesCollection createAdditionalDataset(BarSeries series) {
|
||||
ClosePriceIndicator indicator = new ClosePriceIndicator(series);
|
||||
TimeSeriesCollection dataset = new TimeSeriesCollection();
|
||||
TimeSeries chartTimeSeries = new TimeSeries("Btc price");
|
||||
for (int i = 0; i < series.getBarCount(); i++) {
|
||||
Bar bar = series.getBar(i);
|
||||
chartTimeSeries.add(new Second(new Date(bar.getEndTime().toEpochMilli())),
|
||||
indicator.getValue(i).doubleValue());
|
||||
}
|
||||
dataset.addSeries(chartTimeSeries);
|
||||
return dataset;
|
||||
}
|
||||
|
||||
private static TimeSeriesCollection createChopDataset(BarSeries series) {
|
||||
ChopIndicator indicator = new ChopIndicator(series, CHOP_INDICATOR_TIMEFRAME, CHOP_SCALE_VALUE);
|
||||
TimeSeriesCollection dataset = new TimeSeriesCollection();
|
||||
TimeSeries chartTimeSeries = new TimeSeries("CHOP_14");
|
||||
for (int i = 0; i < series.getBarCount(); i++) {
|
||||
Bar bar = series.getBar(i);
|
||||
if (i < CHOP_INDICATOR_TIMEFRAME)
|
||||
continue;
|
||||
chartTimeSeries.add(new Second(new Date(bar.getEndTime().toEpochMilli())),
|
||||
indicator.getValue(i).doubleValue());
|
||||
}
|
||||
dataset.addSeries(chartTimeSeries);
|
||||
return dataset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a chart in a frame. The frame is configured to avoid stealing focus
|
||||
* when launched from tests or scripts.
|
||||
*
|
||||
* @param ohlcDataset
|
||||
* @param xyDataset
|
||||
* @param chopSeries
|
||||
*/
|
||||
private static void displayChart(XYDataset ohlcDataset, XYDataset xyDataset, XYDataset chopSeries) {
|
||||
/*
|
||||
* Create the chart
|
||||
*/
|
||||
CandlestickRenderer renderer = new CandlestickRenderer();
|
||||
XYPlot pricePlot = new XYPlot(ohlcDataset, xAxis, new NumberAxis("Price"), renderer);
|
||||
renderer.setAutoWidthMethod(CandlestickRenderer.WIDTHMETHOD_SMALLEST);
|
||||
// volume dataset
|
||||
pricePlot.setDataset(VOLUME_DATASET_INDEX, xyDataset);
|
||||
pricePlot.mapDatasetToRangeAxis(VOLUME_DATASET_INDEX, 0);
|
||||
// plot.setDomainAxis( xAxis );
|
||||
XYLineAndShapeRenderer renderer2 = new XYLineAndShapeRenderer(true, false);
|
||||
renderer2.setSeriesPaint(VOLUME_DATASET_INDEX, Color.blue);
|
||||
pricePlot.setRenderer(VOLUME_DATASET_INDEX, renderer2);
|
||||
// Misc
|
||||
pricePlot.setRangeGridlinePaint(Color.lightGray);
|
||||
pricePlot.setBackgroundPaint(Color.white);
|
||||
NumberAxis numberAxis = (NumberAxis) pricePlot.getRangeAxis();
|
||||
pricePlot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
|
||||
renderer.setAutoWidthMethod(CandlestickRenderer.WIDTHMETHOD_SMALLEST);
|
||||
// Misc
|
||||
pricePlot.setRangeGridlinePaint(Color.lightGray);
|
||||
pricePlot.setBackgroundPaint(Color.white);
|
||||
numberAxis.setAutoRangeIncludesZero(false);
|
||||
pricePlot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
|
||||
// secondary study plot
|
||||
indicatorXYPlot = new XYPlot( /* null, xAxis, yAxis, renderer */);
|
||||
indicatorXYPlot.setDataset(chopSeries);
|
||||
indicatorXYPlot.setRangeAxis(0, new NumberAxis(""));
|
||||
indicatorXYPlot.setRenderer(0, new XYLineAndShapeRenderer());
|
||||
NumberAxis yIndicatorAxis = new NumberAxis("");
|
||||
yIndicatorAxis.setRange(0, CHOP_SCALE_VALUE);
|
||||
indicatorXYPlot.setRangeAxis(0, yIndicatorAxis);
|
||||
|
||||
// combinedPlot
|
||||
combinedPlot = new CombinedDomainXYPlot(xAxis); // DateAxis
|
||||
combinedPlot.setGap(10.0);
|
||||
// combinedPlot.setDomainAxis( xAxis );
|
||||
combinedPlot.setBackgroundPaint(Color.LIGHT_GRAY);
|
||||
combinedPlot.setDomainGridlinePaint(Color.GRAY);
|
||||
combinedPlot.setRangeGridlinePaint(Color.GRAY);
|
||||
combinedPlot.setOrientation(PlotOrientation.VERTICAL);
|
||||
combinedPlot.add(pricePlot, 70);
|
||||
combinedPlot.add(indicatorXYPlot, 30);
|
||||
|
||||
// Now create the chart that contains the combinedPlot
|
||||
combinedChart = new JFreeChart("Bitstamp BTC price with Chop indicator", null, combinedPlot, true);
|
||||
combinedChart.setBackgroundPaint(Color.LIGHT_GRAY);
|
||||
|
||||
// combinedChartPanel to contain combinedChart
|
||||
combinedChartPanel = new ChartPanel(combinedChart);
|
||||
combinedChartPanel.setLayout(new GridLayout(0, 1));
|
||||
combinedChartPanel.setBackground(Color.LIGHT_GRAY);
|
||||
combinedChartPanel.setPreferredSize(new Dimension(740, 300));
|
||||
|
||||
// Application frame
|
||||
ApplicationFrame frame = new ApplicationFrame("Ta4j example - Candlestick chart");
|
||||
frame.setContentPane(combinedChartPanel);
|
||||
frame.pack();
|
||||
UIUtils.centerFrameOnScreen(frame);
|
||||
frame.setFocusableWindowState(false);
|
||||
frame.setVisible(true);
|
||||
frame.setAlwaysOnTop(false);
|
||||
frame.setAutoRequestFocus(false);
|
||||
|
||||
// CHOP oscillator upper/lower threshold guidelines
|
||||
XYLineAnnotation lineAnnotation = new XYLineAnnotation(
|
||||
(double) series.getFirstBar().getBeginTime().toEpochMilli(), CHOP_LOWER_THRESHOLD,
|
||||
(double) series.getLastBar().getEndTime().toEpochMilli(), CHOP_LOWER_THRESHOLD, dashedThinLineStyle,
|
||||
Color.GREEN);
|
||||
lineAnnotation.setToolTipText("tradable below this");
|
||||
indicatorXYPlot.addAnnotation(lineAnnotation);
|
||||
lineAnnotation = new XYLineAnnotation((double) series.getFirstBar().getBeginTime().toEpochMilli(),
|
||||
CHOP_UPPER_THRESHOLD, (double) series.getLastBar().getEndTime().toEpochMilli(), CHOP_UPPER_THRESHOLD,
|
||||
dashedThinLineStyle, Color.RED);
|
||||
lineAnnotation.setToolTipText("too choppy above this");
|
||||
indicatorXYPlot.addAnnotation(lineAnnotation);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
series = BitStampCsvTradesFileBarSeriesDataSource.loadBitstampSeries();
|
||||
/*
|
||||
* Create the OHLC dataset from the data series
|
||||
*/
|
||||
OHLCDataset ohlcDataset = createOHLCDataset(series);
|
||||
/*
|
||||
* Create volume dataset
|
||||
*/
|
||||
TimeSeriesCollection xyDataset = createAdditionalDataset(series);
|
||||
/*
|
||||
* add the CHOP Indicator
|
||||
*/
|
||||
TimeSeriesCollection chopSeries = createChopDataset(series);
|
||||
/*
|
||||
* Display the chart
|
||||
*/
|
||||
displayChart(ohlcDataset, xyDataset, chopSeries);
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
package ta4jexamples.indicators;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.jfree.chart.ChartFactory;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.DateAxis;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.ui.ApplicationFrame;
|
||||
import org.jfree.chart.ui.UIUtils;
|
||||
import org.jfree.data.time.Day;
|
||||
import org.jfree.data.time.TimeSeries;
|
||||
import org.jfree.data.time.TimeSeriesCollection;
|
||||
import org.ta4j.core.Bar;
|
||||
import org.ta4j.core.BarSeries;
|
||||
import org.ta4j.core.Indicator;
|
||||
import org.ta4j.core.indicators.averages.EMAIndicator;
|
||||
import org.ta4j.core.indicators.bollinger.BollingerBandsLowerIndicator;
|
||||
import org.ta4j.core.indicators.bollinger.BollingerBandsMiddleIndicator;
|
||||
import org.ta4j.core.indicators.bollinger.BollingerBandsUpperIndicator;
|
||||
import org.ta4j.core.indicators.helpers.ClosePriceIndicator;
|
||||
import org.ta4j.core.indicators.statistics.StandardDeviationIndicator;
|
||||
import org.ta4j.core.num.Num;
|
||||
|
||||
import ta4jexamples.datasources.CsvFileBarSeriesDataSource;
|
||||
|
||||
/**
|
||||
* This class builds a graphical chart showing values from indicators.
|
||||
*/
|
||||
public class IndicatorsToChart {
|
||||
|
||||
/**
|
||||
* Builds a JFreeChart time series from a Ta4j bar series and an indicator.
|
||||
*
|
||||
* @param barSeries the ta4j bar series
|
||||
* @param indicator the indicator
|
||||
* @param name the name of the chart time series
|
||||
* @return the JFreeChart time series
|
||||
*/
|
||||
private static TimeSeries buildChartBarSeries(BarSeries barSeries, Indicator<Num> indicator, String name) {
|
||||
TimeSeries chartTimeSeries = new TimeSeries(name);
|
||||
for (int i = 0; i < barSeries.getBarCount(); i++) {
|
||||
Bar bar = barSeries.getBar(i);
|
||||
chartTimeSeries.add(new Day(Date.from(bar.getEndTime())), indicator.getValue(i).doubleValue());
|
||||
}
|
||||
return chartTimeSeries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a chart in a frame. The frame is configured to avoid stealing focus
|
||||
* when launched from tests or scripts.
|
||||
*
|
||||
* @param chart the chart to be displayed
|
||||
*/
|
||||
private static void displayChart(JFreeChart chart) {
|
||||
// Chart panel
|
||||
ChartPanel panel = new ChartPanel(chart);
|
||||
panel.setFillZoomRectangle(true);
|
||||
panel.setMouseWheelEnabled(true);
|
||||
panel.setPreferredSize(new Dimension(500, 270));
|
||||
// Application frame
|
||||
ApplicationFrame frame = new ApplicationFrame("Ta4j example - Indicators to chart");
|
||||
frame.setContentPane(panel);
|
||||
frame.pack();
|
||||
UIUtils.centerFrameOnScreen(frame);
|
||||
frame.setFocusableWindowState(false);
|
||||
frame.setVisible(true);
|
||||
frame.setAlwaysOnTop(false);
|
||||
frame.setAutoRequestFocus(false);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
/*
|
||||
* Getting bar series
|
||||
*/
|
||||
BarSeries series = CsvFileBarSeriesDataSource.loadSeriesFromFile();
|
||||
|
||||
/*
|
||||
* Creating indicators
|
||||
*/
|
||||
// Close price
|
||||
ClosePriceIndicator closePrice = new ClosePriceIndicator(series);
|
||||
EMAIndicator avg14 = new EMAIndicator(closePrice, 14);
|
||||
StandardDeviationIndicator sd14 = new StandardDeviationIndicator(closePrice, 14);
|
||||
|
||||
// Bollinger bands
|
||||
BollingerBandsMiddleIndicator middleBBand = new BollingerBandsMiddleIndicator(avg14);
|
||||
BollingerBandsLowerIndicator lowBBand = new BollingerBandsLowerIndicator(middleBBand, sd14);
|
||||
BollingerBandsUpperIndicator upBBand = new BollingerBandsUpperIndicator(middleBBand, sd14);
|
||||
|
||||
/*
|
||||
* Building chart dataset
|
||||
*/
|
||||
TimeSeriesCollection dataset = new TimeSeriesCollection();
|
||||
dataset.addSeries(buildChartBarSeries(series, closePrice, "Apple Inc. (AAPL) - NASDAQ GS"));
|
||||
dataset.addSeries(buildChartBarSeries(series, lowBBand, "Low Bollinger Band"));
|
||||
dataset.addSeries(buildChartBarSeries(series, upBBand, "High Bollinger Band"));
|
||||
|
||||
/*
|
||||
* Creating the chart
|
||||
*/
|
||||
JFreeChart chart = ChartFactory.createTimeSeriesChart("Apple Inc. 2013 Close Prices", // title
|
||||
"Date", // x-axis label
|
||||
"Price Per Unit", // y-axis label
|
||||
dataset, // data
|
||||
true, // create legend?
|
||||
true, // generate tooltips?
|
||||
false // generate URLs?
|
||||
);
|
||||
XYPlot plot = (XYPlot) chart.getPlot();
|
||||
DateAxis axis = (DateAxis) plot.getDomainAxis();
|
||||
axis.setDateFormatOverride(new SimpleDateFormat("yyyy-MM-dd"));
|
||||
|
||||
/*
|
||||
* Displaying the chart
|
||||
*/
|
||||
displayChart(chart);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
package ta4jexamples.indicators;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.ta4j.core.BarSeries;
|
||||
import org.ta4j.core.indicators.ATRIndicator;
|
||||
import org.ta4j.core.indicators.PPOIndicator;
|
||||
import org.ta4j.core.indicators.ROCIndicator;
|
||||
import org.ta4j.core.indicators.RSIIndicator;
|
||||
import org.ta4j.core.indicators.WilliamsRIndicator;
|
||||
import org.ta4j.core.indicators.averages.EMAIndicator;
|
||||
import org.ta4j.core.indicators.averages.SMAIndicator;
|
||||
import org.ta4j.core.indicators.helpers.ClosePriceIndicator;
|
||||
import org.ta4j.core.indicators.helpers.ClosePriceRatioIndicator;
|
||||
import org.ta4j.core.indicators.helpers.TypicalPriceIndicator;
|
||||
import org.ta4j.core.indicators.statistics.StandardDeviationIndicator;
|
||||
|
||||
import ta4jexamples.datasources.BitStampCsvTradesFileBarSeriesDataSource;
|
||||
|
||||
/**
|
||||
* This class builds a CSV file containing values from indicators.
|
||||
*/
|
||||
public class IndicatorsToCsv {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(IndicatorsToCsv.class);
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
/*
|
||||
* Getting bar series
|
||||
*/
|
||||
BarSeries series = BitStampCsvTradesFileBarSeriesDataSource.loadBitstampSeries();
|
||||
|
||||
/*
|
||||
* Creating indicators
|
||||
*/
|
||||
// Close price
|
||||
ClosePriceIndicator closePrice = new ClosePriceIndicator(series);
|
||||
// Typical price
|
||||
TypicalPriceIndicator typicalPrice = new TypicalPriceIndicator(series);
|
||||
// Price variation
|
||||
ClosePriceRatioIndicator closePriceRatioIndicator = new ClosePriceRatioIndicator(series);
|
||||
// Simple moving averages
|
||||
SMAIndicator shortSma = new SMAIndicator(closePrice, 8);
|
||||
SMAIndicator longSma = new SMAIndicator(closePrice, 20);
|
||||
// Exponential moving averages
|
||||
EMAIndicator shortEma = new EMAIndicator(closePrice, 8);
|
||||
EMAIndicator longEma = new EMAIndicator(closePrice, 20);
|
||||
// Percentage price oscillator
|
||||
PPOIndicator ppo = new PPOIndicator(closePrice, 12, 26);
|
||||
// Rate of change
|
||||
ROCIndicator roc = new ROCIndicator(closePrice, 100);
|
||||
// Relative strength index
|
||||
RSIIndicator rsi = new RSIIndicator(closePrice, 14);
|
||||
// Williams %R
|
||||
WilliamsRIndicator williamsR = new WilliamsRIndicator(series, 20);
|
||||
// Average true range
|
||||
ATRIndicator atr = new ATRIndicator(series, 20);
|
||||
// Standard deviation
|
||||
StandardDeviationIndicator sd = new StandardDeviationIndicator(closePrice, 14);
|
||||
|
||||
/*
|
||||
* Building header
|
||||
*/
|
||||
StringBuilder sb = new StringBuilder(
|
||||
"timestamp,close,typical,variation,sma8,sma20,ema8,ema20,ppo,roc,rsi,williamsr,atr,sd\n");
|
||||
|
||||
/*
|
||||
* Adding indicators values
|
||||
*/
|
||||
final int nbBars = series.getBarCount();
|
||||
for (int i = 0; i < nbBars; i++) {
|
||||
sb.append(series.getBar(i).getEndTime())
|
||||
.append(',')
|
||||
.append(closePrice.getValue(i))
|
||||
.append(',')
|
||||
.append(typicalPrice.getValue(i))
|
||||
.append(',')
|
||||
.append(closePriceRatioIndicator.getValue(i))
|
||||
.append(',')
|
||||
.append(shortSma.getValue(i))
|
||||
.append(',')
|
||||
.append(longSma.getValue(i))
|
||||
.append(',')
|
||||
.append(shortEma.getValue(i))
|
||||
.append(',')
|
||||
.append(longEma.getValue(i))
|
||||
.append(',')
|
||||
.append(ppo.getValue(i))
|
||||
.append(',')
|
||||
.append(roc.getValue(i))
|
||||
.append(',')
|
||||
.append(rsi.getValue(i))
|
||||
.append(',')
|
||||
.append(williamsR.getValue(i))
|
||||
.append(',')
|
||||
.append(atr.getValue(i))
|
||||
.append(',')
|
||||
.append(sd.getValue(i))
|
||||
.append('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* Writing CSV file
|
||||
*/
|
||||
BufferedWriter writer = null;
|
||||
try {
|
||||
writer = new BufferedWriter(new FileWriter(new File("target", "indicators.csv")));
|
||||
writer.write(sb.toString());
|
||||
} catch (IOException ioe) {
|
||||
LOG.error("Unable to write CSV file", ioe);
|
||||
} finally {
|
||||
try {
|
||||
if (writer != null) {
|
||||
writer.close();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user