/*******************************************************************************
* 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.algo;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.quantcomponents.core.model.IContract;
import com.quantcomponents.core.model.ISeries;
import com.quantcomponents.core.model.ISeriesAugmentable;
import com.quantcomponents.core.model.ISeriesListener;
import com.quantcomponents.core.model.ISeriesPoint;
import com.quantcomponents.core.model.ISeriesProcessor;
import com.quantcomponents.core.series.SimplePoint;
/**
* Provides the equity curve for an algorithm run, based on the position data-points in the algo execution output series
*/
public class EquityCurveProcessor implements ISeriesProcessor<Date, Double>, ISeriesListener<Date, Double> {
public static final String INPUT_SERIES_NAME = "POSITIONS";
private final Map<IContract, IPosition> positions = new ConcurrentHashMap<IContract, IPosition>();
private volatile ISeries<Date, Double, ? extends ISeriesPoint<Date, Double>> inputSeries;
private volatile ISeriesAugmentable<Date, Double, ISeriesPoint<Date, Double>> outputSeries;
@Override
public void wire(Map<String, ? extends ISeries<Date, Double, ? extends ISeriesPoint<Date, Double>>> inputSeriesMap, ISeriesAugmentable<Date, Double, ISeriesPoint<Date, Double>> outputSeries) {
this.inputSeries = inputSeriesMap.get(INPUT_SERIES_NAME);
this.outputSeries = outputSeries;
if (!inputSeries.isEmpty()) {
for (ISeriesPoint<Date, Double> point : this.inputSeries) {
onItemAdded(point);
}
}
this.inputSeries.addSeriesListener(this);
}
@Override
public void unwire() {
if (inputSeries != null) {
inputSeries.removeSeriesListener(this);
inputSeries = null;
}
outputSeries = null;
}
private void onPositionUpdate(IContract contract, IPosition position) {
positions.put(contract, position);
double pnl = calculatePnl();
SimplePoint point = new SimplePoint(position.getTimestamp(), pnl);
if (outputSeries != null) {
outputSeries.insertFromTail(point);
}
}
private double calculatePnl() {
double pnl = 0.0;
for (IPosition position : positions.values()) {
pnl += position.getUnrealizedPnl();
pnl += position.getRealizedPnl();
}
return pnl;
}
@Override
public void onItemUpdated(ISeriesPoint<Date, Double> existingItem, ISeriesPoint<Date, Double> updatedItem) { }
@Override
public void onItemAdded(ISeriesPoint<Date, Double> newItem) {
if (newItem instanceof IPositionPoint) {
IPositionPoint positionPoint = (IPositionPoint) newItem;
onPositionUpdate(positionPoint.getContract(), positionPoint.getPosition());
}
}
}