Related
I am writing a Java program by using the Binance JAVA API to retrieve the 1-minute interval candelsticks of a trading pair. Using this Java class, I want to calculate the EMA (Exponential Moving Average) of the past 10 days.
The Binance JAVA API websocket implementation gets the latest depth events, which also contains the current closing price that I use to update the EMA calculation by calling the EMA#update method.
However, I notice that the EMA showing on the Binance's graph, does not correspond to the ones I get from my code. Also, I notice that the values need some time to 'settle' before giving (somewhat) same values compared to those shown on Binance.
On TradingView I found a formula to calculate the EMA (that shows the same EMA value as on Binance), but that is different than the one used in the EMA class. However, even when using this formula, the values are very different than the one on Binance.
Could someone help me figure out what the issue is and how to obtain the same values?
UPDATE 1: code provided
import java.util.*;
import java.util.stream.Collectors;
import com.binance.api.client.BinanceApiClientFactory;
import com.binance.api.client.BinanceApiRestClient;
import com.binance.api.client.BinanceApiWebSocketClient;
import com.binance.api.client.domain.market.Candlestick;
import com.binance.api.client.domain.market.CandlestickInterval;
import core.util.text.DecimalFormat;
import core.util.text.StringUtil;
public class test_003
{
private Map<Long, Candlestick> candlesticksCache = new TreeMap<>();
private EMA EMA_10;
private EMA EMA_20;
public static void main(String[] pArgs)
{
new test_003();
}
private test_003()
{
Locale.setDefault(Locale.US);
candlesticksCacheExample("ADAUSDT", CandlestickInterval.ONE_MINUTE);
}
private void candlesticksCacheExample(String symbol, CandlestickInterval interval)
{
initializeCandlestickCache(symbol, interval);
startCandlestickEventStreaming(symbol, interval);
}
private void initializeCandlestickCache(String symbol, CandlestickInterval interval)
{
BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance();
BinanceApiRestClient client = factory.newRestClient();
List<Candlestick> candlestickBars_10 = client.getCandlestickBars(symbol.toUpperCase(), interval, Integer.valueOf(11), null, null);
List<Candlestick> candlestickBars_20 = client.getCandlestickBars(symbol.toUpperCase(), interval, Integer.valueOf(21), null, null);
List<Double> closingPriceList_10 = candlestickBars_10.stream().map(c -> Double.valueOf(c.getClose())).collect(Collectors.toList());
List<Double> closingPriceList_20 = candlestickBars_20.stream().map(c -> Double.valueOf(c.getClose())).collect(Collectors.toList());
EMA_10 = new EMA(closingPriceList_10, Integer.valueOf(10));
EMA_20 = new EMA(closingPriceList_20, Integer.valueOf(20));
}
private void startCandlestickEventStreaming(String symbol, CandlestickInterval interval)
{
BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance();
BinanceApiWebSocketClient client = factory.newWebSocketClient();
client.onCandlestickEvent(symbol.toLowerCase(), interval, response -> {
Long openTime = response.getOpenTime();
Candlestick updateCandlestick = candlesticksCache.get(openTime);
if (updateCandlestick == null)
{
// new candlestick
updateCandlestick = new Candlestick();
}
// update candlestick with the stream data
updateCandlestick.setOpenTime(response.getOpenTime());
updateCandlestick.setOpen(response.getOpen());
updateCandlestick.setLow(response.getLow());
updateCandlestick.setHigh(response.getHigh());
updateCandlestick.setClose(response.getClose());
updateCandlestick.setCloseTime(response.getCloseTime());
updateCandlestick.setVolume(response.getVolume());
updateCandlestick.setNumberOfTrades(response.getNumberOfTrades());
updateCandlestick.setQuoteAssetVolume(response.getQuoteAssetVolume());
updateCandlestick.setTakerBuyQuoteAssetVolume(response.getTakerBuyQuoteAssetVolume());
updateCandlestick.setTakerBuyBaseAssetVolume(response.getTakerBuyQuoteAssetVolume());
// Store the updated candlestick in the cache
candlesticksCache.put(openTime, updateCandlestick);
double closingPrice = Double.valueOf(updateCandlestick.getClose());
EMA_10.update(closingPrice);
EMA_20.update(closingPrice);
System.out.println(StringUtil.replacePlaceholders("Closing price: %1 | EMA(10): %2 - EMA(20): %3", response.getClose(),
DecimalFormat.format(EMA_10.get(), "#.#####"),
DecimalFormat.format(EMA_20.get(), "#.#####")));
});
}
public class EMA
{
private double currentEMA;
private final int period;
private final double multiplier;
private final List<Double> EMAhistory;
private final boolean historyNeeded;
private String fileName;
public EMA(List<Double> closingPrices, int period)
{
this(closingPrices, period, false);
}
public EMA(List<Double> closingPrices, int period, boolean historyNeeded)
{
currentEMA = 0;
this.period = period;
this.historyNeeded = historyNeeded;
this.multiplier = 2.0 / (double) (period + 1);
this.EMAhistory = new ArrayList<>();
init(closingPrices);
}
public double get()
{
return currentEMA;
}
public double getTemp(double newPrice)
{
return (newPrice - currentEMA) * multiplier + currentEMA;
}
public void init(List<Double> closingPrices)
{
if (period > closingPrices.size()) return;
//Initial SMA
for (int i = 0; i < period; i++)
{
currentEMA += closingPrices.get(i);
}
currentEMA = currentEMA / (double) period;
if (historyNeeded) EMAhistory.add(currentEMA);
//Dont use latest unclosed candle;
for (int i = period; i < closingPrices.size() - 1; i++)
{
update(closingPrices.get(i));
}
}
public void update(double newPrice)
{
// EMA = (Close - EMA(previousBar)) * multiplier + EMA(previousBar)
currentEMA = (newPrice - currentEMA) * multiplier + currentEMA;
if (historyNeeded) EMAhistory.add(currentEMA);
}
public int check(double newPrice)
{
return 0;
}
public String getExplanation()
{
return null;
}
public List<Double> getEMAhistory()
{
return EMAhistory;
}
public int getPeriod()
{
return period;
}
}
}
UPDATE 2
The problem is that onCandlestickEvent is not just called when a candle is completed, but actually multiple times per minute (every 2 seconds or so). The data that you are receiving in the response spans the time from when the candle is opened until the event time of the response, whether the candle is completed or not.
To see what I mean, you could replace the System.out() statement in your startCandlestickEventStreaming method with the following:
System.out.println(response.getOpenTime() + ";" +
response.getEventTime() + ";" +
response.getCloseTime());
You will see that the close time of the candle actually lies in the future.
In order to update your EMA correctly, you will have to wait until the candle has actually been completed. You could store the open time of the tentative candle in a member variable, check if it has changed since the last time onCandlestickEvent was called, and then update your EMA with the final close value of the candle:
client.onCandlestickEvent(symbol.toLowerCase(), interval, response -> {
Long openTime = response.getOpenTime();
Candlestick updateCandlestick = candlesticksCache.get(openTime);
if (updateCandlestick == null)
{
// new candlestick
updateCandlestick = new Candlestick();
}
// update candlestick with the stream data
...
// Store the updated candlestick in the cache
candlesticksCache.put(openTime, updateCandlestick);
if (openTime > m_LastOpenTime)
{
// need to get the close of the PREVIOUS candle
Candlestick previousCandle = candlesticksCache.get(m_LastOpenTime);
double closingPrice = Double.valueOf(previousCandle.getClose());
EMA_10.update(closingPrice);
EMA_20.update(closingPrice);
System.out.println(StringUtil.replacePlaceholders("Closing price: %1 | EMA(10): %2 - EMA(20): %3", response.getClose(),
DecimalFormat.format(EMA_10.get(), "#.#####"),
DecimalFormat.format(EMA_20.get(), "#.#####")));
m_LastOpenTime = openTime;
}
});
You'll probably get an exception on the first response, because there are no candles on the stack yet and we don't have a m_LastOpenTime. You could get the current server time before calling client.onCandlestickEvent():
private void startCandlestickEventStreaming(String symbol, CandlestickInterval interval)
{
BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance();
BinanceApiWebSocketClient client = factory.newWebSocketClient();
BinanceApiRestClient restClient = factory.newRestClient();
m_LastOpenTime = restClient.getServerTime();
client.onCandlestickEvent(symbol.toLowerCase(), interval, response -> {
...
}
}
I noticed there's actually a much simpler way than my other answer. I'm leaving that one up, however, because it could still be relevant for dealing with a dodgy connection where you can't necessarily rely on always getting the final candlestick with your response.
The response.getBarFinal()) method allows for testing whether the response you have received is the final candlestick or if it is just an intermediate one. If you change your code as follows, your EMA will only get updated with the final close value of the candle as it should be:
if (response.getBarFinal())
{
double closingPrice = Double.valueOf(updateCandlestick.getClose());
EMA_10.update(closingPrice);
EMA_20.update(closingPrice);
System.out.println(StringUtil.replacePlaceholders("Closing price: %1 | EMA(10): %2 - EMA(20): %3", response.getClose(),
DecimalFormat.format(EMA_10.get(), "#.#####"),
DecimalFormat.format(EMA_20.get(), "#.#####")));
}
When i create test for Google Or-Tools and send my distance matrix, solution the solution is always null.
When i use default distance matrix from here https://developers.google.com/optimization/routing/vrp
but when i use my custom distanceMatrix array Assigment solution is always null.
Where is mistake?
Full test class
import com.google.ortools.constraintsolver.*;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.logging.Logger;
#RunWith(SpringRunner.class)
#SpringBootTest
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class OrToolsTests {
private static final Logger logger = Logger.getLogger(OrToolsTests.class.getName());
static {
System.loadLibrary("jniortools");
}
#Test
public void b_googleOrTools() throws Exception {
// Instantiate the data problem.
final DataModel data = new DataModel();
// Create Routing Index Manager
RoutingIndexManager manager =
new RoutingIndexManager(data.data.length, data.vehicleNumber, data.depot);
// Create Routing Model.
RoutingModel routing = new RoutingModel(manager);
// Create and register a transit callback.
final int transitCallbackIndex =
routing.registerTransitCallback((long fromIndex, long toIndex) -> {
// Convert from routing variable Index to user NodeIndex.
int fromNode = manager.indexToNode(fromIndex);
int toNode = manager.indexToNode(toIndex);
return data.data[fromNode][toNode];
});
// Define cost of each arc.
routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
// Add Distance constraint.
routing.addDimension(transitCallbackIndex, 0, 3000,
true, // start cumul to zero
"Distance");
RoutingDimension distanceDimension = routing.getMutableDimension("Distance");
distanceDimension.setGlobalSpanCostCoefficient(100);
// Setting first solution heuristic.
RoutingSearchParameters searchParameters =
main.defaultRoutingSearchParameters()
.toBuilder()
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
.build();
// Solve the problem.
Assignment solution = routing.solveWithParameters(searchParameters);
// Print solution on console.
printSolution(data, routing, manager, solution);
}
private void printSolution(
DataModel data, RoutingModel routing, RoutingIndexManager manager, Assignment solution) {
// Inspect solution.
long maxRouteDistance = 0;
for (int i = 0; i < data.vehicleNumber; ++i) {
long index = routing.start(i);
logger.info("Route for Vehicle " + i + ":");
long routeDistance = 0;
String route = "";
while (!routing.isEnd(index)) {
route += manager.indexToNode(index) + " -> ";
long previousIndex = index;
index = solution.value(routing.nextVar(index));
routeDistance += routing.getArcCostForVehicle(previousIndex, index, i);
}
logger.info(route + manager.indexToNode(index));
logger.info("Distance of the route: " + routeDistance + "m");
maxRouteDistance = Math.max(routeDistance, maxRouteDistance);
}
logger.info("Maximum of the route distances: " + maxRouteDistance + "m");
}
class DataModel {
public final long[][] data = {
{0, 58305, 41338, 16599, 22834, 36364, 24979, 9797, 22023, 5880, 21282, 39248},
{58147, 0, 82634, 49102, 39605, 93558, 72909, 49687, 67379, 55889, 76274, 22047},
{41663, 81167, 0, 47046, 58798, 56366, 18071, 41586, 60532, 36117, 49432, 74933},
{15666, 49990, 53000, 0, 7358, 51077, 30428, 13558, 34534, 13408, 33793, 30933},
{22151, 39552, 59486, 7391, 0, 57563, 36914, 20043, 41019, 19893, 40278, 24535},
{36164, 93036, 56237, 51331, 57566, 0, 37419, 44529, 44381, 41822, 17567, 73980},
{25224, 72585, 18046, 30880, 37115, 37483, 0, 25147, 44093, 19678, 30549, 53529},
{9218, 49544, 41424, 13485, 19719, 44630, 25065, 0, 28086, 5966, 27345, 30488},
{22816, 72597, 60379, 34430, 40665, 44423, 44020, 27629, 0, 24921, 27138, 57079},
{6858, 56163, 36826, 14458, 20693, 42270, 20467, 6781, 25726, 0, 24985, 37107},
{22678, 75998, 49002, 34292, 40527, 17284, 30184, 27490, 27342, 24783, 0, 56941},
{38986, 22165, 76018, 29941, 24347, 74398, 53749, 30526, 57854, 36728, 57113, 0}};
public final int vehicleNumber = 4;
public final int depot = 0;
}
}
From what I understand, you add a dimension with a max cumul of 3000, while the distance matrix has a lot of inter-node distances above 10k.
The 3000 value in #addDimension represents the vehicle maximum travel distance. Since the values in your distance matrix are higher, or-tools is not able to find a solution.
To fix this you have to change the 3000 value so that it is higher than the highest value in your distance matrix. For example
change
// Add Distance constraint.
routing.addDimension(transitCallbackIndex, 0, 3000,
true, // start cumul to zero
"Distance");
to
// Add Distance constraint.
routing.addDimension(transitCallbackIndex, 0, 100000,
true, // start cumul to zero
"Distance");
and your code will work.
Introduction
My goal is to input a set of products and choose an option for display such as:
System.out.print("Input number of products to represent: ");
prodNum = scan.nextInt();
String[] prodName = new String[prodNum];
System.out.print("Enter which products to represent: ");
for (int i = 0; i < prodName.length; i++)
{
prodName[i] = scan.next();
}
System.out.println("----Options----");
System.out.println("1. Cantidad");
System.out.println("2. Calidad");
System.out.println("3. RealmQ");
System.out.println("4. Coste");
option = scan.nextInt();
userOptionWas(option);
then by using JFreeCharts I wanted to be able to choose how many lines (for each product I input) and what option to display (quantity, quality and stuff) which is stored inside some obviously named arrays.
My approach
private XYDataset multipleLine(int prodNum, String[] prodName, int option){
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries product3 = new XYSeries("product3");
XYSeries product4 = new XYSeries("product4");
XYSeries product5 = new XYSeries("product5");
XYSeries product6 = new XYSeries("product6");
XYSeries product7 = new XYSeries("product7");
XYSeries product8 = new XYSeries("product8");
switch(prodNum)
{
case(2):
{
if (option == 1)
{
XYSeries product1 = new XYSeries(prodName[0]);
XYSeries product2 = new XYSeries(prodName[1]);
for (int i = 0; i < CSVinput.cantidad.length; i++)
{
try
{
if (CSVinput.nombre[i].equals(prodName[0]))
{
product1.add(i, CSVinput.cantidad[i]);
}
}catch(ArrayIndexOutOfBoundsException e){}
}
}
if (option == 2)
{
}
if (option == 3)
{
}
if (option == 4)
{
}
}
}
return dataset;
}
Halfway through implementing my idea I started to wonder if it is not possible to do it, or just I am in the wrong path to my goal.
What I expect
I want to be able to create different plots from a simple menu I showed before.
If it is possible, dynamic (if I input 2 products the program displays 2 lines referring to each product)
Extra Notes
I am new at JFreeCharts.
Take a moment here at product1.add(i, CSVinput.cantidad[i]); where I use (int)"i" instead of my (String)"date" format. Why I am not able to use a String? Is there any way to bypass this?
What I expect from this question
I would like to know more efficient and friendly ways to achieve this without too much unnecessary complexity.
Data Example
2018/12/29-Tejido,321 908,13.55,43.18,$15.98,
2018/12/29-Ropa,195 045,20.55,45.93,$123.01,
2018/12/29-Gorra de visera,126 561,17.43,42.32,$79.54,
2018/12/29-Cerveza,80 109,3.37,17.93,$12.38,
2018/12/29-Mercancías de playa,75 065,11.48,39.73,$105.93,
2018/12/29-Bebidas alcohólicas,31 215,4.84,27.90,$32.29,
2018/12/29-Artículos de cuero,19 098,23.13,44.09,$198.74,
2018/12/29-Bolsas y carteras,7 754,23.09,41.34,$1 176.54,
2018/12/30-Tejido,252 229,12.86,43.14,$18.87,
2018/12/30-Ropa,132 392,18.09,46.02,$177.58,
2018/12/30-Gorra de visera,87 676,14.42,42.46,$122.48,
2018/12/30-Cerveza,44 593,2.72,17.79,$18.71,
2018/12/30-Mercancías de playa,44 593,8.26,39.56,$200.78,
2018/12/30-Bebidas alcohólicas,27 306,4.30,23.88,$31.95,
2018/12/30-Artículos de cuero,16 147,21.08,43.91,$207.49,
2018/12/30-Bolsas y carteras,6 552,21.11,40.59,$1 195.41,
2019/01/02-Tejido,321 908,13.55,43.18,$15.98,
2019/01/02-Ropa,195 045,20.55,45.93,$123.01,
2019/01/02-Gorra de visera,126 561,17.43,42.32,$79.54,
2019/01/02-Cerveza,80 109,3.37,17.93,$12.38,
2019/01/02-Mercancías de playa,75 065,11.48,39.73,$105.93,
2019/01/02-Bebidas alcohólicas,31 215,4.84,27.90,$32.29,
2019/01/02-Artículos de cuero,19 098,23.13,44.09,$198.74,
2019/01/02-Bolsas y carteras,7 754,23.09,41.34,$1 176.54,
2019/01/03-Tejido,1 164 607,12.87,43.14,$15.54,
2019/01/03-Ropa,131 409,17.18,45.97,$161.17,
2019/01/03-Gorra de visera,79 242,13.54,43.17,$100.38,
2019/01/03-Cerveza,48 332,2.80,18.10,$17.48,
2019/01/03-Mercancías de playa,46 157,8.70,38.39,$180.54,
2019/01/03-Bebidas alcohólicas,25 210,4.04,23.72,$33.52,
2019/01/03-Artículos de cuero,14 321,19.56,39.92,$216.00,
2019/01/03-Bolsas y carteras,5 814,19.85,39.68,$1 227.29,
EDIT:
Thanks a lot for the help I think I have learnt but the way is never ending as by some reason, the instance which takes the dataset does not plot the dataset
What I am missing?.
PD: Let me know in the comments if you need CSVinput in order to provide a solution.
import java.awt.Color;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.Scanner;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.general.SeriesException;
import org.jfree.data.time.Day;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
import webscrapper.CSVinput;
/**
*
* #author Jonathan
*/
public class TimeSeriesChartExample extends ApplicationFrame{
//To parse dates below and be able to debug outside the loop
public static String[] dateSplit;
//Instace that declares properties and uses the dataset to create the chart
public TimeSeriesChartExample(String title)
{
super(title);
// Create dataset
XYDataset dataset = createDataset();
// Create chart
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"Titulo", // Chart
"Date", // X-Axis Label
"Number", // Y-Axis Label
dataset);
//Changes background color
XYPlot plot = (XYPlot)chart.getPlot();
plot.setBackgroundPaint(new Color(255,228,196));
}
//Create the set of data to be plotted
private XYDataset createDataset()
{
//A collection of datasets
TimeSeriesCollection dataset = new TimeSeriesCollection();
//The object were this new series are added thus it's name
TimeSeries prod1 = new TimeSeries("Cantidad");
//"For each" name stored in the array
for (int i = 0; i < CSVinput.nombre.length; i++)
{
//If name equals
if ("Ropa".equals(CSVinput.nombre[i]))
{
//Pass the "i" position to work it
dateSplit = CSVinput.fecha[i].split("/");
//Parse the date
int day = Integer.parseInt(dateSplit[2]);
int month = Integer.parseInt(dateSplit[1]);
int year = Integer.parseInt(dateSplit[0]);
System.out.println("day is: " + day);
//Pass the parsed date and the value from CSV.cantidad at "i" position referring to the name "Ropa"
prod1.add(new Day(day, month, year), CSVinput.cantidad[i]);
System.out.println(CSVinput.cantidad[i]);//Debug stuff
}
}
//Add everything to the dataset
dataset.addSeries(prod1);
//Return it
return dataset;
}
private XYDataset createDataset2()
{
//A collection of datasets
TimeSeriesCollection dataset = new TimeSeriesCollection();
//The object were this new series are added thus it's name
TimeSeries prod2 = new TimeSeries("Cantidad");
//"For each" name stored in the array
for (int i = 0; i < CSVinput.nombre.length; i++)
{
//If name equals
if (CSVinput.nombre[i] == "Tejido")
{
//Pass the "i" position to work it
dateSplit = CSVinput.fecha[i].split("/");
//Parse the date
int day = Integer.parseInt(dateSplit[0]);
int month = Integer.parseInt(dateSplit[1]);
int year = Integer.parseInt(dateSplit[2]);
//Pass the parsed date and the value from CSV.cantidad at "i" position referring to the name "Ropa"
prod2.add(new Day(day, month, year), CSVinput.cantidad[i]);
System.out.println(CSVinput.cantidad[i]);//Debug stuff
}
}
//Add everything to the dataset
dataset.addSeries(prod2);
//Return it
return dataset;
}
public static void main(String[] args) throws FileNotFoundException
{
//Custom class to import data from the csv into arrays (TODO: make it dynamic)
CSVinput.ImportData("caca.csv");
/* //More debugg stuff
dateSplit = CSVinput.fecha[1].split("/");
System.out.println("year: " + dateSplit[0] + " month: " + dateSplit[1] + " day: " + dateSplit[2]);
*/
//Create an instance of the previous class
final TimeSeriesChartExample example = new TimeSeriesChartExample("ItWorks!");
example.pack(); //Part from the ApplicationFrame
RefineryUtilities.centerFrameOnScreen(example); //Render the graph at the center of screen
example.setVisible(true); //make it visible
}
}
First, focus on you program's data model:
If your series include a time domain, consider using a TimeSeriesCollection of TimeSeries rather than XYSeries; TimeSeriesChartDemo1, cited here, is a basic example; parse dates as shown here and here; for database access, consider a JDBCXYDataset.
As you read the data for each series, store the series in a List<TimeSeries>, rather than an array; if latency is a problem, do the parsing in the background, as shown here.
The exact details will depend on your application's design, but using the observer pattern will minimize complexity; the basic principle is to update the model (Dataset) and the listening view (JFreeChart) will update itself in response. Using Swing for example, you can control the displayed chart in several ways:
Use your List<TimeSeries> to construct a suitable ListModel<TimeSeries>; for the series menu, make your chosen model a DefaultComboBoxModel<TimeSeries> for a JComboBox or a DefaultListModel<TimeSeries> for a JList.
Add a suitable listener to your menu component; give your XYPlot a TimeSeriesCollection; use addSeries() or removeSeries() to alter the plot as a series is selected; alternatively, use setSeriesVisible() to toggle visibility, as shown here.
For a command-line interface, the interactions are less complex but also less versatile:
Use a List<TimeSeries> to build your TimeSeriesCollection.
Use the TimeSeriesCollection methods to control what the listening XYPlot displays.
I'm testing this class
/**
* Class to classify irises based on petal and sepal measurements.
*
* #author James Howard <jh#jameshoward.us>
*/
package us.jameshoward.iristypes;
import java.io.InputStream;
import java.util.Dictionary;
import java.util.Enumeration;
import weka.classifiers.Classifier;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.SerializationHelper;
public class Iris {
private Classifier classModel;
private Instances dataModel;
private String classModelFile = "/Irises/etc/iris.model";
/**
* Class constructor.
*/
public Iris() throws Exception {
InputStream classModelStream;
// Create a stream object for the model file embedded
// within the JAR file.
classModelStream = getClass().getResourceAsStream(classModelFile);
classModel = (Classifier)SerializationHelper.read(classModelStream) ;
}
/**
* Close the instance by setting both the model file string and
* the model object itself to null. When the garbage collector
* runs, this should make clean up simpler. However, the garbage
* collector is not called synchronously since that should be
* managed by the larger execution environment.
*/
public void close() {
classModel = null;
classModelFile = null;
}
/**
* Evaluate the model on the data provided by #param measures.
* This returns a string with the species name.
*
* #param measures object with petal and sepal measurements
* #return string with the species name
* #throws Exception
*/
public String classifySpecies(Dictionary<String, String> measures) throws Exception {
#SuppressWarnings("rawtypes")
FastVector dataClasses = new FastVector();
FastVector dataAttribs = new FastVector();
Attribute species;
double values[] = new double[measures.size() + 1];
int i = 0, maxIndex = 0;
// Assemble the potential species options.
dataClasses.addElement("setosa");
dataClasses.addElement("versicolor");
dataClasses.addElement("virginica");
species = new Attribute("species", dataClasses);
// Create the object to classify on.
for (Enumeration<String> keys = measures.keys(); keys.hasMoreElements(); ) {
String key = keys.nextElement();
double val = Double.parseDouble(measures.get(key));
dataAttribs.addElement(new Attribute(key));
values[i++] = val;
}
dataAttribs.addElement(species);
dataModel = new Instances("classify", dataAttribs, 0);
dataModel.setClass(species);
dataModel.add(new Instance(1, values));
dataModel.instance(0).setClassMissing();
// Find the class with the highest estimated likelihood
double cl[] = classModel.distributionForInstance(dataModel.instance(0));
for(i = 0; i < cl.length; i++)
if(cl[i] > cl[maxIndex])
maxIndex = i;
return dataModel.classAttribute().value(maxIndex);
}
}
when start initialising its instance from another class with
Iris irisModel = new Iris();
i got following error
Exception in thread "main" java.io.IOException: Stream closed
at java.io.BufferedInputStream.getInIfOpen(BufferedInputStream.java:159)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
at java.io.ObjectInputStream$PeekInputStream.read(ObjectInputStream.java:2320)
at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2333)
at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:2804)
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:802)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299)
at weka.core.SerializationHelper.read(SerializationHelper.java:288)
at us.jameshoward.iristypes.Iris.<init>(Iris.java:33)
at us.jameshoward.iristypes.IrisDriver.main(IrisDriver.java:11)
I guess this error is case specific, by comparing with other posts, i still cant find out where it went wrong. in fact, this class was downloaded from IBMknowledge website, it supposes to be error-proof i guess.
anyone knows how to fix this?
thanks
How can I pause a genetic algorithm in Encog 3.4 (the version currently under development in Github)?
I am using the Java version of Encog.
I am trying to modify the Lunar example that comes with Encog. I want to pause/serialize the genetic algorithm and then continue/deserialize at a later stage.
When I call train.pause(); it simply returns null - which is pretty obvious from the code since the method always returns null.
I would assume that it would be pretty straight forward since there can be a scenario in which I want to train a neural network, use it for some predictions and then continue training with the genetic algorithm as I get more data before resuming with more predictions - without having to restart the training from the beginning.
Please note that I am not trying to serialize or persist a neural network but rather the entire genetic algorithm.
Not all trainers in Encog support the simple pause/resume. If they do not support it, they return null, like this one. The genetic algorithm trainer is much more complex than a simple propagation trainer that supports pause/resume. To save the state of the genetic algorithm, you must save the entire population, as well as the scoring function (which may or may not be serializable). I modified the Lunar Lander example to show you how you might save/reload your population of neural networks to do this.
You can see that it trains 50 iterations, then round-trips (load/saves) the genetic algorithm, then trains 50 more.
package org.encog.examples.neural.lunar;
import java.io.File;
import java.io.IOException;
import org.encog.Encog;
import org.encog.engine.network.activation.ActivationTANH;
import org.encog.ml.MLMethod;
import org.encog.ml.MLResettable;
import org.encog.ml.MethodFactory;
import org.encog.ml.ea.population.Population;
import org.encog.ml.genetic.MLMethodGeneticAlgorithm;
import org.encog.ml.genetic.MLMethodGenomeFactory;
import org.encog.neural.networks.BasicNetwork;
import org.encog.neural.pattern.FeedForwardPattern;
import org.encog.util.obj.SerializeObject;
public class LunarLander {
public static BasicNetwork createNetwork()
{
FeedForwardPattern pattern = new FeedForwardPattern();
pattern.setInputNeurons(3);
pattern.addHiddenLayer(50);
pattern.setOutputNeurons(1);
pattern.setActivationFunction(new ActivationTANH());
BasicNetwork network = (BasicNetwork)pattern.generate();
network.reset();
return network;
}
public static void saveMLMethodGeneticAlgorithm(String file, MLMethodGeneticAlgorithm ga ) throws IOException
{
ga.getGenetic().getPopulation().setGenomeFactory(null);
SerializeObject.save(new File(file),ga.getGenetic().getPopulation());
}
public static MLMethodGeneticAlgorithm loadMLMethodGeneticAlgorithm(String filename) throws ClassNotFoundException, IOException {
Population pop = (Population) SerializeObject.load(new File(filename));
pop.setGenomeFactory(new MLMethodGenomeFactory(new MethodFactory(){
#Override
public MLMethod factor() {
final BasicNetwork result = createNetwork();
((MLResettable)result).reset();
return result;
}},pop));
MLMethodGeneticAlgorithm result = new MLMethodGeneticAlgorithm(new MethodFactory(){
#Override
public MLMethod factor() {
return createNetwork();
}},new PilotScore(),1);
result.getGenetic().setPopulation(pop);
return result;
}
public static void main(String args[])
{
BasicNetwork network = createNetwork();
MLMethodGeneticAlgorithm train;
train = new MLMethodGeneticAlgorithm(new MethodFactory(){
#Override
public MLMethod factor() {
final BasicNetwork result = createNetwork();
((MLResettable)result).reset();
return result;
}},new PilotScore(),500);
try {
int epoch = 1;
for(int i=0;i<50;i++) {
train.iteration();
System.out
.println("Epoch #" + epoch + " Score:" + train.getError());
epoch++;
}
train.finishTraining();
// Round trip the GA and then train again
LunarLander.saveMLMethodGeneticAlgorithm("/Users/jeff/projects/trainer.bin",train);
train = LunarLander.loadMLMethodGeneticAlgorithm("/Users/jeff/projects/trainer.bin");
// Train again
for(int i=0;i<50;i++) {
train.iteration();
System.out
.println("Epoch #" + epoch + " Score:" + train.getError());
epoch++;
}
train.finishTraining();
} catch(IOException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int epoch = 1;
for(int i=0;i<50;i++) {
train.iteration();
System.out
.println("Epoch #" + epoch + " Score:" + train.getError());
epoch++;
}
train.finishTraining();
System.out.println("\nHow the winning network landed:");
network = (BasicNetwork)train.getMethod();
NeuralPilot pilot = new NeuralPilot(network,true);
System.out.println(pilot.scorePilot());
Encog.getInstance().shutdown();
}
}