/*
* Copyright (c) 2004-2011 Marco Maccaferri and others.
* 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:
* Marco Maccaferri - initial API and implementation
*/
package org.eclipsetrader.core.internal.ats;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import org.eclipsetrader.core.ats.IStrategy;
import org.eclipsetrader.core.ats.ITradingSystem;
import org.eclipsetrader.core.ats.ITradingSystemContext;
import org.eclipsetrader.core.ats.ITradingSystemInstrument;
import org.eclipsetrader.core.ats.engines.EngineEvent;
import org.eclipsetrader.core.ats.engines.JavaScriptEngine;
import org.eclipsetrader.core.feed.IQuote;
import org.eclipsetrader.core.feed.ITrade;
import org.eclipsetrader.core.instruments.ISecurity;
import org.eclipsetrader.core.trading.IPosition;
public class TradingSystem implements ITradingSystem {
private final IStrategy strategy;
private TradingSystemProperties properties;
private final Map<ISecurity, TradingSystemInstrument> instruments = new HashMap<ISecurity, TradingSystemInstrument>();
private JavaScriptEngine engine;
private int status = STATUS_STOPPED;
private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
private final Observer observer = new Observer() {
@Override
public void update(Observable o, Object arg) {
EngineEvent event = (EngineEvent) arg;
TradingSystemInstrument instrument = instruments.get(event.instrument);
if (instrument == null) {
return;
}
if (event.value instanceof IPosition) {
IPosition position = (IPosition) event.value;
instrument.setPosition(position.getQuantity() != 0 ? position : null);
}
if (event.value instanceof IQuote) {
instrument.setQuote((IQuote) event.value);
}
if (event.value instanceof ITrade) {
instrument.setTrade((ITrade) event.value);
}
}
};
private final PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!IStrategy.PROP_INSTRUMENTS.equals(evt.getPropertyName())) {
return;
}
boolean changed = false;
ITradingSystemInstrument[] oldInstruments = getInstruments();
ISecurity[] security = (ISecurity[]) evt.getNewValue();
for (int i = 0; i < security.length; i++) {
if (!instruments.containsKey(security[i])) {
instruments.put(security[i], new TradingSystemInstrument(security[i]));
changed = true;
}
}
Set<ISecurity> set = new HashSet<ISecurity>(Arrays.asList(security));
for (Iterator<ISecurity> iter = instruments.keySet().iterator(); iter.hasNext();) {
if (!set.contains(iter.next())) {
iter.remove();
changed = true;
}
}
if (changed) {
changeSupport.firePropertyChange(PROPERTY_INSTRUMENTS, oldInstruments, getInstruments());
}
}
};
public TradingSystem(IStrategy strategy) {
this.strategy = strategy;
this.properties = new TradingSystemProperties();
for (ISecurity security : strategy.getInstruments()) {
instruments.put(security, new TradingSystemInstrument(security));
}
PropertyChangeSupport propertyChangeSupport = (PropertyChangeSupport) strategy.getAdapter(PropertyChangeSupport.class);
if (propertyChangeSupport != null) {
propertyChangeSupport.addPropertyChangeListener(propertyChangeListener);
}
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
changeSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
changeSupport.addPropertyChangeListener(listener);
}
public void dispose() {
PropertyChangeSupport propertyChangeSupport = (PropertyChangeSupport) strategy.getAdapter(PropertyChangeSupport.class);
if (propertyChangeSupport != null) {
propertyChangeSupport.removePropertyChangeListener(propertyChangeListener);
}
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.ats.ITradingSystem#getStatus()
*/
@Override
public int getStatus() {
return status;
}
public void setStatus(int status) {
changeSupport.firePropertyChange(PROPERTY_STATUS, this.status, this.status = status);
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.ats.ITradingSystem#getStrategy()
*/
@Override
public IStrategy getStrategy() {
return strategy;
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.ats.ITradingSystem#getInstruments()
*/
@Override
public ITradingSystemInstrument[] getInstruments() {
Collection<TradingSystemInstrument> c = new ArrayList<TradingSystemInstrument>(instruments.values());
return c.toArray(new ITradingSystemInstrument[c.size()]);
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.ats.ITradingSystem#start(org.eclipsetrader.core.ats.ITradingSystemContext)
*/
@Override
public void start(ITradingSystemContext context) throws Exception {
for (TradingSystemInstrument instrument : instruments.values()) {
instrument.setQuote(null);
instrument.setTrade(null);
}
for (IPosition position : context.getAccount().getPositions()) {
TradingSystemInstrument instrument = instruments.get(position.getSecurity());
if (instrument != null) {
instrument.setPosition(position);
}
}
engine = new JavaScriptEngine(this, context);
engine.addObserver(observer);
engine.start();
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.ats.ITradingSystem#stop()
*/
@Override
public void stop() {
if (engine != null) {
engine.deleteObserver(observer);
engine.stop();
engine.dispose();
engine = null;
}
for (TradingSystemInstrument instrument : instruments.values()) {
instrument.setQuote(null);
instrument.setTrade(null);
}
}
public TradingSystemProperties getProperties() {
return properties;
}
public void setProperties(TradingSystemProperties properties) {
this.properties = properties;
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
@Override
@SuppressWarnings({
"unchecked", "rawtypes"
})
public Object getAdapter(Class adapter) {
if (adapter.isAssignableFrom(strategy.getClass())) {
return strategy;
}
if (adapter.isAssignableFrom(properties.getClass())) {
return properties;
}
if (adapter.isAssignableFrom(changeSupport.getClass())) {
return changeSupport;
}
if (adapter.isAssignableFrom(getClass())) {
return this;
}
return null;
}
}