/*******************************************************************************
* Copyright (c) 2013 Luigi Sgro. All rights reserved. This
* program and the accompanying materials are made available under the terms of
* the Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Luigi Sgro - initial API and implementation
******************************************************************************/
package com.quantcomponents.ui.algo;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.part.ViewPart;
import com.quantcomponents.algo.EquityCurveProcessor;
import com.quantcomponents.chart.series.LevelSeriesRenderer;
import com.quantcomponents.chart.series.TimeSeriesChart;
import com.quantcomponents.core.model.IMutableSeries;
import com.quantcomponents.core.model.ISeries;
import com.quantcomponents.core.model.ISeriesPoint;
import com.quantcomponents.core.series.LinkedListSeries;
import com.quantcomponents.core.utils.LangUtils;
public class EquityCurveView extends ViewPart implements ISelectionListener {
public static final String VIEW_ID = "com.quantcomponents.ui.algo.equityCurve";
private static final long DEFAULT_INTERVAL = 24L * 60L * 60L * 1000L;
private static final int MARGIN_LEFT = 10;
private static final int MARGIN_TOP = 10;
private static final int MARGIN_RIGHT = 50;
private static final int MARGIN_BOTTOM = 20;
private static class ExecutionInfo {
public ExecutionInfo(EquityCurveProcessor processor, IMutableSeries<Date, Double, ISeriesPoint<Date, Double>> outputSeries) {
this.processor = processor;
this.outputSeries = outputSeries;
}
EquityCurveProcessor processor;
IMutableSeries<Date, Double, ISeriesPoint<Date, Double>> outputSeries;
}
private final Map<TradingAgentExecutionWrapper, ExecutionInfo> executionMap = new HashMap<TradingAgentExecutionWrapper, ExecutionInfo>();
private volatile Composite parent;
private volatile ExecutionInfo currentExecutionInfo;
private volatile TimeSeriesChart chart;
@Override
public void createPartControl(Composite parent) {
this.parent = parent;
chart = new TimeSeriesChart(parent, SWT.NONE);
chart.setSeriesRenderer(new LevelSeriesRenderer());
chart.setMargins(MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM);
getSite().getPage().addSelectionListener(this);
selectionChanged(null, getSite().getPage().getSelection());
}
@Override
public void setFocus() {
}
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if (selection instanceof IStructuredSelection) {
IStructuredSelection structured = (IStructuredSelection) selection;
Object object = structured.getFirstElement();
if (object instanceof TradingAgentExecutionWrapper) {
final TradingAgentExecutionWrapper executionWrapper = (TradingAgentExecutionWrapper) object;
try {
getViewSite().getWorkbenchWindow().run(true, false, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) {
ExecutionInfo executionInfo = executionMap.get(executionWrapper);
if (executionInfo == null) {
EquityCurveProcessor processor = new EquityCurveProcessor();
String processorOutputSeriesID = "output-" + processor.toString();
ISeries<Date, Double, ISeriesPoint<Date, Double>> executionOutputSeries = executionWrapper.getManager().getExecutionOutput(executionWrapper.getHandle());
executionInfo = new ExecutionInfo(processor, new LinkedListSeries<Date, Double, ISeriesPoint<Date, Double>>(processorOutputSeriesID, false));
executionInfo.processor.wire(Collections.singletonMap(EquityCurveProcessor.INPUT_SERIES_NAME, executionOutputSeries), executionInfo.outputSeries);
executionMap.put(executionWrapper, executionInfo);
}
currentExecutionInfo = executionInfo;
chart.setSeries(currentExecutionInfo.outputSeries);
chart.setPointInterval(calculateInitialPointInterval(currentExecutionInfo.outputSeries));
chart.refresh();
}});
} catch (Exception e) {
MessageDialog.openError(parent.getShell(), "Equity curve update failed", LangUtils.exceptionMessage(e));
}
}
}
}
@Override
public void dispose() {
for (ExecutionInfo executionInfo : executionMap.values()) {
executionInfo.processor.unwire();
}
}
private long calculateInitialPointInterval(ISeries<Date, Double, ISeriesPoint<Date, Double>> series) {
if (series.isEmpty()) {
return DEFAULT_INTERVAL;
} else {
return Math.max((series.getLast().getIndex().getTime() - series.getFirst().getIndex().getTime()) / series.size(), 1);
}
}
}