repo: sandbox, rev: r480 - in activequant-base/trunk/activequant-framework/src: main/java/org/activequant/broker main/java/org/activequant/container/report main/java/org/activequant/container/report/statistics main/java/org/activequant/core/domainmodel/data main/java/org/activequant/util main/java/org/activequant/util/log main/java/org/activequant/util/tools test/java/org/activequant/util test/java/org/activequant/util/log

View: New views
4 Messages — Rating Filter:   Alert me  

repo: sandbox, rev: r480 - in activequant-base/trunk/activequant-framework/src: main/java/org/activequant/broker main/java/org/activequant/container/report main/java/org/activequant/container/report/statistics main/java/org/activequant/core/domainmodel/data main/java/org/activequant/util main/java/org/activequant/util/log main/java/org/activequant/util/tools test/java/org/activequant/util test/java/org/activequant/util/log

by Lars Wilke-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Author: ustaudinger
Date: 2009-10-05 13:38:59 +0200 (Mon, 05 Oct 2009)
New Revision: 480

Added:
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/core/domainmodel/data/TimedValue.java
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/core/domainmodel/data/ValueSeries.java
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/CsvLogger.java
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/IAQLogger.java
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/LoggerBase.java
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/MultiLoggerFacade.java
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/PnlLogger.java
   activequant-base/trunk/activequant-framework/src/test/java/org/activequant/util/log/
   activequant-base/trunk/activequant-framework/src/test/java/org/activequant/util/log/CsvLoggerTest.java
   activequant-base/trunk/activequant-framework/src/test/java/org/activequant/util/log/PnlLoggerTest.java
Modified:
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/broker/PaperBroker.java
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/container/report/TextReportingService.java
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/container/report/statistics/AverageOrderSize.java
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/tools/Hexdump.java
   activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/tools/XMLParser.java
Log:
Added a logging facade for live logging, as well as unit test for it.

Modified: activequant-base/trunk/activequant-framework/src/main/java/org/activequant/broker/PaperBroker.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/main/java/org/activequant/broker/PaperBroker.java 2009-09-30 18:11:13 UTC (rev 479)
+++ activequant-base/trunk/activequant-framework/src/main/java/org/activequant/broker/PaperBroker.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -39,6 +39,7 @@
 import org.activequant.core.types.TimeStamp;
 import org.activequant.data.retrieval.IQuoteSubscriptionSource;
 import org.activequant.data.retrieval.ISubscription;
+import org.activequant.util.log.IAQLogger;
 import org.activequant.util.pattern.events.IEventListener;
 import org.activequant.util.tools.UniqueDateGenerator;
 
@@ -57,6 +58,7 @@
 public class PaperBroker extends BrokerBase {
 
  private IQuoteSubscriptionSource subscriptionSource;
+ private IAQLogger logger;
  private double commissionPerExecution = 0.0;
  private final UniqueDateGenerator timeStampGenerator = new UniqueDateGenerator();
  private final AtomicLong orderId = new AtomicLong();
@@ -302,6 +304,23 @@
  }
  }
 
+ /**
+ * the AQ Logger implementation.
+ * @return
+ */
+ public IAQLogger getLogger() {
+ return logger;
+ }
+
+ /**
+ * injector for the AQ logger.
+ * @param logger
+ */
+ public void setLogger(IAQLogger logger) {
+ this.logger = logger;
+ }
+
+
  @Override
  protected OrderTracker createOrderTracker(Order order) {
  switch(order.getOrderType()) {

Modified: activequant-base/trunk/activequant-framework/src/main/java/org/activequant/container/report/TextReportingService.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/main/java/org/activequant/container/report/TextReportingService.java 2009-09-30 18:11:13 UTC (rev 479)
+++ activequant-base/trunk/activequant-framework/src/main/java/org/activequant/container/report/TextReportingService.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -122,7 +122,6 @@
  out.println(o.toString());
  }
 
-
  out.println();
  out.close();
  }

Modified: activequant-base/trunk/activequant-framework/src/main/java/org/activequant/container/report/statistics/AverageOrderSize.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/main/java/org/activequant/container/report/statistics/AverageOrderSize.java 2009-09-30 18:11:13 UTC (rev 479)
+++ activequant-base/trunk/activequant-framework/src/main/java/org/activequant/container/report/statistics/AverageOrderSize.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -11,10 +11,11 @@
 
 /**
  *
- * @author ustaudinger
+ * @author Ulrich Staudinger
  */
 public class AverageOrderSize implements IStatisticsComputer {
 
+
     public void compute(Hashtable<String, Object> aStack, Object anObject)
     {
         int myOrderCount = 0;

Added: activequant-base/trunk/activequant-framework/src/main/java/org/activequant/core/domainmodel/data/TimedValue.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/main/java/org/activequant/core/domainmodel/data/TimedValue.java                        (rev 0)
+++ activequant-base/trunk/activequant-framework/src/main/java/org/activequant/core/domainmodel/data/TimedValue.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -0,0 +1,192 @@
+/****
+
+    activequant - activestocks.eu
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+ contact  : contact@...
+    homepage : http://www.activestocks.eu
+
+****/
+package org.activequant.core.domainmodel.data;
+
+import static org.activequant.util.tools.IdentityUtils.safeCompare;
+import static org.activequant.util.tools.IdentityUtils.safeHashCode;
+import static org.activequant.util.tools.IdentityUtils.equalsTo;
+
+import org.activequant.core.domainmodel.InstrumentSpecification;
+import org.activequant.core.types.TimeStamp;
+import org.activequant.core.util.TimeStampFormat;
+
+/**
+ * Represents a single price move of the market.
+ * <br>
+ * <em>IMPORTANT</em>: This object has "value" identity.
+ * It means that its identity
+ * (hashCode, equals, and comapreTo) is determined by subset of the fields,
+ * declared "business keys". Other fields are considered a "payload".
+ * This identity reflects the suggested unique key constraints in the
+ * related sql table.
+ * <em>IMPORTANT</em>: If this object is added to a collection that relies on
+ * identity, changing business key will break the collection
+ * contract and will cause unexpected results.
+ *
+ */
+public class TimedValue extends MarketDataEntity<TimedValue> {
+
+ private static final long serialVersionUID = 7789600340466925266L;
+
+ /**
+     * contains the value we track.
+     */
+    private double value = NOT_SET;
+    
+    /**
+     * just a very flat constructor.
+     *
+     */
+    public TimedValue() {
+    
+    }
+    
+    public TimedValue(TimeStamp date) {
+     super(date);
+    }
+    
+    public TimedValue(InstrumentSpecification spec) {
+     super(spec);
+    }
+    
+    public TimedValue(InstrumentSpecification spec,
+     TimeStamp date) {
+     this(date);
+     setInstrumentSpecification(spec);
+ }
+    
+    public TimedValue(InstrumentSpecification spec, double value) {
+     super(spec);
+     this.value = value;  
+    }
+    
+
+    public TimedValue(InstrumentSpecification spec,
+     TimeStamp date, double value) {
+     this(date);
+     setInstrumentSpecification(spec);
+     setValue(value);
+    }
+    
+    
+    /**
+     * constructor.
+     * @param priceIndication
+     *
+     */
+    public TimedValue(double tick) {
+     this.value = tick;    
+    }
+    
+    public TimedValue(TimeStamp date, double tick) {
+     super(date);
+     this.value = tick;
+    }
+    
+    
+    /**
+     * return object's state as string.
+     * @return text
+     */
+    @Override
+ public String toString(){
+     TimeStampFormat sdf = new TimeStampFormat("dd.MM.yyyy HH:mm:ss.SSS");
+     return getClass().getSimpleName()
+     + "{spec=" + getInstrumentSpecification()
+     + ", timeStamp=" + sdf.format(getTimeStamp()) + "(" + getTimeStamp() + "L)"
+     + ", value=" + getValue()
+     + "}";
+    }
+
+    /**
+     * clone this instance.
+     * @return cloned object
+     */
+    @Override
+ public TimedValue clone() {
+ return new TimedValue(getInstrumentSpecification(), getTimeStamp(),
+ value);
+ }
+
+    /**
+     * {@inheritDoc}
+     */
+ public int compareTo(TimedValue other) {
+ // ATTENTION: keep in sync with hashCode();
+ int rc;
+
+ if((rc = safeCompare(this.getInstrumentSpecification(),
+ other.getInstrumentSpecification())) != 0) {
+ return rc;
+ }
+ if((rc = safeCompare(this.getTimeStamp(), other.getTimeStamp())) != 0) {
+ return rc;
+ }
+ if((rc = safeCompare(this.value, other.value)) != 0) {
+ return rc;
+ }
+
+ return 0;
+ }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+ public int hashCode() {
+ // ATTENTION: keep in sync with compareTo();
+        return safeHashCode(this.getInstrumentSpecification())
+         + safeHashCode(this.getTimeStamp())
+         + safeHashCode(this.value);
+ }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object other) {
+     return equalsTo(this, other);
+ }
+
+ public double getValue() {
+ return value;
+ }
+
+ /**
+ * sets the value.
+ * @param value.
+ */
+ public void setValue(double tradedPrice) {
+ this.value = tradedPrice;
+ }
+
+ public double[] getDoubles() {
+ return new double[] { value };
+ }
+
+ public void setDoubles(double[] values) {
+ assert(values.length == 1) : "values.length != 1)";
+ setValue(values[0]);
+ }
+}
\ No newline at end of file

Added: activequant-base/trunk/activequant-framework/src/main/java/org/activequant/core/domainmodel/data/ValueSeries.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/main/java/org/activequant/core/domainmodel/data/ValueSeries.java                        (rev 0)
+++ activequant-base/trunk/activequant-framework/src/main/java/org/activequant/core/domainmodel/data/ValueSeries.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -0,0 +1,18 @@
+package org.activequant.core.domainmodel.data;
+
+/**
+ * a plain value series.
+ *
+ * @author Ulrich Staudinger
+ */
+public class ValueSeries extends TimeSeries<TimedValue> {
+
+ @Override
+ public TimeSeries<TimedValue> clone() {
+ ValueSeries myRet = new ValueSeries();
+ for(TimedValue myValue : this)
+ myRet.add(myValue);
+ return myRet;
+ }
+
+}

Added: activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/CsvLogger.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/CsvLogger.java                        (rev 0)
+++ activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/CsvLogger.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -0,0 +1,197 @@
+package org.activequant.util.log;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.util.HashMap;
+
+import javax.swing.text.NumberFormatter;
+
+import org.activequant.core.domainmodel.InstrumentSpecification;
+import org.activequant.core.domainmodel.account.Order;
+import org.activequant.core.domainmodel.data.Quote;
+import org.activequant.core.domainmodel.events.OrderCancelEvent;
+import org.activequant.core.domainmodel.events.OrderCompletionEvent;
+import org.activequant.core.domainmodel.events.OrderErrorEvent;
+import org.activequant.core.domainmodel.events.OrderEvent;
+import org.activequant.core.domainmodel.events.OrderExecutionEvent;
+import org.activequant.core.domainmodel.events.OrderRejectEvent;
+import org.activequant.core.domainmodel.events.OrderUpdateEvent;
+import org.activequant.core.types.OrderSide;
+
+/**
+ * The CSV Logger logs business logic events to a file. In this implementation,
+ * it starts a new log file and does not append to an existing file, in case the
+ * filename provided in the constructor points to an existing file. <br>
+ * <br>
+ * The output file is a csv file, with at least three columns: <br>
+ * - TimeStamp in nanoseconds<br>
+ * - Instrument Specification ID<br>
+ * - Log Event Type<br>
+ * - Additional event specific payload<br>
+ * <br>
+ * History<br>
+ * - [5.10.2009] Created (Ulrich Staudinger)<br>
+ *
+ * @author Ulrich Staudinger
+ *
+ */
+public class CsvLogger extends LoggerBase {
+
+ public CsvLogger(OutputStream aCommonStream, OutputStream aPnlStream)
+ throws IOException {
+ theWriter = new BufferedWriter(new OutputStreamWriter(aCommonStream));
+ thePnlWriter = new BufferedWriter(new OutputStreamWriter(aPnlStream));
+ }
+
+ public void announceInstrumentSpecifications(
+ InstrumentSpecification... aSpecs) {
+ for (InstrumentSpecification mySpec : aSpecs) {
+ long myIId = mySpec.getId();
+ if (!thePositions.containsKey(myIId)) {
+ thePositions.put(myIId, 0.0);
+ theInstrumentValuationPrices.put(myIId, 0.0);
+ }
+ }
+ }
+
+ public void log(Order anOrder, OrderEvent anEvent) {
+ try {
+ StringBuffer mySb = new StringBuffer();
+
+ mySb.append("" + anEvent.getEventTimeStamp().getNanoseconds()
+ + ";");
+
+ if (anEvent instanceof OrderCancelEvent) {
+ append(mySb, anOrder, (OrderCancelEvent) anEvent);
+ } else if (anEvent instanceof OrderCompletionEvent) {
+ append(mySb, anOrder, (OrderCompletionEvent) anEvent);
+ } else if (anEvent instanceof OrderErrorEvent) {
+ } else if (anEvent instanceof OrderExecutionEvent) {
+ append(mySb, anOrder, (OrderExecutionEvent) anEvent);
+ } else if (anEvent instanceof OrderUpdateEvent) {
+ append(mySb, anOrder, (OrderUpdateEvent) anEvent);
+ } else if (anEvent instanceof OrderRejectEvent) {
+
+ }
+ String myInstrumentId = "";
+ theWriter.write(myInstrumentId);
+
+ } catch (IOException e) {
+ exception(e);
+ }
+ }
+
+ private void append(StringBuffer anSb, Order anOrder) {
+ anSb.append("" + anOrder.getInstrumentSpecification().getId());
+ anSb.append(";OrderSubmit;");
+ anSb.append(anOrder.getOrderSide().name() + ";");
+ anSb.append(anOrder.getOrderType().name() + ";");
+ anSb.append(anOrder.getLimitPrice() + ";");
+ anSb.append(anOrder.getLimitPrice() + ";");
+ anSb.append("\n");
+ }
+
+ private void append(StringBuffer anSb, Order anOrder,
+ OrderCancelEvent anEvent) {
+ anSb.append("" + anOrder.getInstrumentSpecification().getId());
+ anSb.append(";OrderCancel;");
+ anSb.append(anEvent.getMessage());
+ anSb.append("\n");
+ }
+
+ private void append(StringBuffer anSb, Order anOrder,
+ OrderCompletionEvent anEvent) {
+ anSb.append("" + anOrder.getInstrumentSpecification().getId());
+ anSb.append(";OrderCompletion;");
+ anSb.append(anEvent.getAveragePrice() + ";");
+ anSb.append(anEvent.getTotalQuantity() + ";");
+ anSb.append(anEvent.getTotalCommission() + ";");
+ anSb.append("\n");
+ }
+
+ private void append(StringBuffer anSb, Order anOrder,
+ OrderExecutionEvent anEvent) {
+ long myIId = anOrder.getInstrumentSpecification().getId();
+ anSb.append("" + myIId);
+ anSb.append(";OrderExecution;");
+ anSb.append(anEvent.getPrice() + ";");
+ anSb.append(anEvent.getQuantity() + ";");
+ anSb.append(anEvent.getCommission() + ";");
+ anSb.append("\n");
+
+ // as it is an order execution, we also update the running positions and
+ // position values.
+ if (!thePositions.containsKey(myIId)) {
+ thePositions.put(myIId, 0.0);
+ theInstrumentValuationPrices.put(myIId, anEvent.getPrice());
+ }
+ // update the position count.
+ double myCurrentPosition = thePositions.get(myIId);
+ // update the last price as well as the current position
+ if (anOrder.getOrderSide().equals(OrderSide.BUY)) {
+ thePositions.put(myIId, myCurrentPosition + anEvent.getQuantity());
+ } else {
+ thePositions.put(myIId, myCurrentPosition
+ - Math.abs(anEvent.getQuantity()));
+ }
+ try {
+ theWriter.write(anSb.toString() + "\n");
+ theWriter.flush();
+ } catch (IOException e) {
+ exception(e);
+ }
+ }
+
+ private void append(StringBuffer anSb, Order anOrder,
+ OrderUpdateEvent anEvent) {
+ anSb.append("" + anOrder.getInstrumentSpecification().getId());
+ anSb.append(";OrderUpdate;");
+ anSb.append(anEvent.getUpdatedOrder() + ";");
+ anSb.append("\n");
+ }
+
+ public void exception(Exception anException) {
+ anException.printStackTrace();
+ }
+
+ /**
+ * the logging of quotes reevaluates the current positions. It is highly
+ * recommended that quotes are immediately sent out (by the log using class)
+ * after executions happen.
+ *
+ */
+ public void log(Quote aQuote) {
+ long myIId = aQuote.getInstrumentSpecification().getId();
+
+ // update the position count.
+ double myCurrentPosition = thePositions.get(myIId);
+ double myLastPrice = theInstrumentValuationPrices.get(myIId);
+ double myRelevantQuotePrice = myCurrentPosition > 0 ? aQuote
+ .getBidPrice() : aQuote.getAskPrice();
+ double myChangeInPrice = myCurrentPosition > 0 ? (aQuote.getBidPrice() - myLastPrice)
+ : (myLastPrice - aQuote.getAskPrice());
+ //
+ double myChangeInPnl = myChangeInPrice * myCurrentPosition;
+ thePnl += (myChangeInPnl / aQuote.getInstrumentSpecification()
+ .getTickSize())
+ * aQuote.getInstrumentSpecification().getTickValue();
+ // track the current valuation price.
+ theInstrumentValuationPrices.put(myIId, myRelevantQuotePrice);
+ //
+ try {
+ thePnlWriter.append(aQuote.getTimeStamp().getNanoseconds()
+ + ";;PNL;" + theNumberFormat.valueToString(thePnl) + "\n");
+ thePnlWriter.flush();
+ } catch (Exception e) {
+ exception(e);
+ }
+
+ }
+
+ private NumberFormatter theNumberFormat = new NumberFormatter();
+ private BufferedWriter theWriter;
+ private BufferedWriter thePnlWriter;
+ private double thePnl = 0.0;
+}

Added: activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/IAQLogger.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/IAQLogger.java                        (rev 0)
+++ activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/IAQLogger.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -0,0 +1,38 @@
+package org.activequant.util.log;
+
+import org.activequant.core.domainmodel.account.Order;
+import org.activequant.core.domainmodel.data.Quote;
+import org.activequant.core.domainmodel.events.OrderEvent;
+
+/**
+ *
+ * The AQ Logger interface defines methods and functionality
+ * for logging Busines Logic related events. <br>
+ * <br>
+ * Implementations of this could for example log all orders
+ * to a separate reporting database or audited reporting system. <br>
+ * <br>
+ * History<br>
+ * - [05.10.2009] Created (Ulrich Staudinger)<br/>
+ *
+ *
+ * @author Ulrich Staudinger
+ *
+ *
+ *
+ */
+public interface IAQLogger {
+
+ /**
+ * use this to log all types of order events.
+ * @param anEvent
+ */
+ public void log(Order anOrder, OrderEvent anEvent);
+
+ /**
+ * Can be used to log a quote, for example for risk reasons
+ * @param aQuote
+ */
+ public void log(Quote aQuote);
+
+}

Added: activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/LoggerBase.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/LoggerBase.java                        (rev 0)
+++ activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/LoggerBase.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -0,0 +1,25 @@
+package org.activequant.util.log;
+
+import java.util.HashMap;
+
+import org.activequant.core.domainmodel.InstrumentSpecification;
+
+public abstract class LoggerBase implements IAQLogger {
+
+ public void announceInstrumentSpecifications(
+ InstrumentSpecification... aSpecs) {
+ for (InstrumentSpecification mySpec : aSpecs) {
+ long myIId = mySpec.getId();
+ if (!thePositions.containsKey(myIId)) {
+ thePositions.put(myIId, 0.0);
+ theInstrumentValuationPrices.put(myIId, 0.0);
+ }
+ }
+ }
+
+ protected HashMap<Long, Double> thePositions = new HashMap<Long, Double>();
+ protected HashMap<Long, Double> thePositionValue = new HashMap<Long, Double>();
+ protected HashMap<Long, Double> theInstrumentValuationPrices = new HashMap<Long, Double>();
+
+
+}

Added: activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/MultiLoggerFacade.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/MultiLoggerFacade.java                        (rev 0)
+++ activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/MultiLoggerFacade.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -0,0 +1,43 @@
+package org.activequant.util.log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.activequant.core.domainmodel.account.Order;
+import org.activequant.core.domainmodel.data.Quote;
+import org.activequant.core.domainmodel.events.OrderEvent;
+
+/**
+ * This is a facade to forward or dispatch a log request to multiple
+ * sub loggers. For example, instantiate it with an instance of a
+ * PnlLogger and a CSVLogger and inject this facade into the
+ * PaperBroker in order to get pnl values logged on the fly. <br>
+ * <br>
+ * History: <br>
+ * - [05.10.2009] Created (Ulrich Staudinger)<br>
+ * <br>
+ *
+ * @author Ulrich Staudinger
+ *
+ */
+public class MultiLoggerFacade implements IAQLogger {
+
+ public MultiLoggerFacade(IAQLogger ... aLoggers)
+ {
+ for(IAQLogger myLogger : aLoggers)
+ theLoggers.add(myLogger);
+ }
+
+ public void log(Order anOrder, OrderEvent anEvent) {
+ for(IAQLogger myLogger : theLoggers)
+ myLogger.log(anOrder, anEvent);
+ }
+
+ public void log(Quote aQuote) {
+ for(IAQLogger myLogger : theLoggers)
+ myLogger.log(aQuote);
+ }
+
+ private List<IAQLogger> theLoggers = new ArrayList<IAQLogger>();
+
+}

Added: activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/PnlLogger.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/PnlLogger.java                        (rev 0)
+++ activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/log/PnlLogger.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -0,0 +1,67 @@
+package org.activequant.util.log;
+
+import org.activequant.core.domainmodel.account.Order;
+import org.activequant.core.domainmodel.data.Quote;
+import org.activequant.core.domainmodel.data.TimedValue;
+import org.activequant.core.domainmodel.data.ValueSeries;
+import org.activequant.core.domainmodel.events.OrderEvent;
+import org.activequant.core.domainmodel.events.OrderExecutionEvent;
+import org.activequant.core.types.OrderSide;
+
+public class PnlLogger extends LoggerBase {
+
+ public void log(Order anOrder, OrderEvent anEvent) {
+ if(anEvent instanceof OrderExecutionEvent)
+ {
+ OrderExecutionEvent myEvent = (OrderExecutionEvent)anEvent;
+ long myIId = anOrder.getInstrumentSpecification().getId();
+ // as it is an order execution, we also update the running positions and
+ // position values.
+ if (!thePositions.containsKey(myIId)) {
+ thePositions.put(myIId, 0.0);
+ theInstrumentValuationPrices.put(myIId, myEvent.getPrice());
+ }
+ // update the position count.
+ double myCurrentPosition = thePositions.get(myIId);
+ // update the last price as well as the current position
+ if (anOrder.getOrderSide().equals(OrderSide.BUY)) {
+ thePositions.put(myIId, myCurrentPosition + myEvent.getQuantity());
+ } else {
+ thePositions.put(myIId, myCurrentPosition
+ - Math.abs(myEvent.getQuantity()));
+ }
+ }
+ }
+
+ public void log(Quote aQuote) {
+ long myIId = aQuote.getInstrumentSpecification().getId();
+
+ // update the position count.
+ double myCurrentPosition = thePositions.get(myIId);
+ double myLastPrice = theInstrumentValuationPrices.get(myIId);
+ double myRelevantQuotePrice = myCurrentPosition > 0 ? aQuote
+ .getBidPrice() : aQuote.getAskPrice();
+ double myChangeInPrice = myCurrentPosition > 0 ? (aQuote.getBidPrice() - myLastPrice)
+ : (myLastPrice - aQuote.getAskPrice());
+ //
+ double myChangeInPnl = myChangeInPrice * myCurrentPosition;
+ thePnl += (myChangeInPnl / aQuote.getInstrumentSpecification().getTickSize()) * aQuote.getInstrumentSpecification().getTickValue();
+ // track the current valuation price.
+ theInstrumentValuationPrices.put(myIId, myRelevantQuotePrice);
+ //
+ TimedValue myValue = new TimedValue(aQuote.getTimeStamp(), thePnl);
+ thePnlValueSeries.add(myValue);
+ }
+
+ /**
+ * the getter for the pnl value series.
+ * @return
+ */
+ public ValueSeries getPnlValueSeries()
+ {
+ return thePnlValueSeries;
+ }
+
+ private double thePnl = 0.0;
+ private ValueSeries thePnlValueSeries = new ValueSeries();
+}

Modified: activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/tools/Hexdump.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/tools/Hexdump.java 2009-09-30 18:11:13 UTC (rev 479)
+++ activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/tools/Hexdump.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -33,6 +33,12 @@
  */
 public class Hexdump {
 
+ /**
+ * Pass in a byte array, get back a string representation in hex.
+ *
+ * @param data a byte array.
+ * @return a hex dump string.
+ */
  public static String hexdump(byte[] data) {
  StringBuffer ret = new StringBuffer();
  int padding = 1;

Modified: activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/tools/XMLParser.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/tools/XMLParser.java 2009-09-30 18:11:13 UTC (rev 479)
+++ activequant-base/trunk/activequant-framework/src/main/java/org/activequant/util/tools/XMLParser.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -146,9 +146,12 @@
 
  /**
  * use this method to print an xml node to a string representation.
- * Node in, String out.
- * @param n
- * @return
+ * Node in, String out. I have to admit, this method is quite
+ * simple and not very advanced. It does not convert CData, but works
+ * very fine for xml nodes, names, text content and attribute values.
+ *
+ * @param n a node.
+ * @return a string representation of the node object.
  */
  public static String toXml(Node n){
  StringBuffer sb = new StringBuffer();

Added: activequant-base/trunk/activequant-framework/src/test/java/org/activequant/util/log/CsvLoggerTest.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/test/java/org/activequant/util/log/CsvLoggerTest.java                        (rev 0)
+++ activequant-base/trunk/activequant-framework/src/test/java/org/activequant/util/log/CsvLoggerTest.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -0,0 +1,79 @@
+package org.activequant.util.log;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+
+import org.activequant.core.domainmodel.InstrumentSpecification;
+import org.activequant.core.domainmodel.account.Order;
+import org.activequant.core.domainmodel.data.Quote;
+import org.activequant.core.domainmodel.events.OrderExecutionEvent;
+import org.activequant.core.types.OrderSide;
+import org.activequant.core.types.OrderType;
+import org.activequant.core.types.TimeStamp;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CsvLoggerTest {
+
+ private CsvLogger theLogger;
+ private ByteArrayOutputStream thePnlStream;
+ private ByteArrayOutputStream theCommonStream;
+ private InstrumentSpecification theSpec1, theSpec2;  
+
+ @Before
+ public void setUp() throws Exception {
+ thePnlStream = new ByteArrayOutputStream();
+ theCommonStream = new ByteArrayOutputStream();
+ theLogger = new CsvLogger(theCommonStream, thePnlStream);
+ theSpec1 = new InstrumentSpecification();
+ // assuming a plain ETF or stock.
+ theSpec1.setTickSize(1.0);
+ theSpec1.setTickValue(1.0);
+ theSpec1.setId(1L);
+ // assuming a dax.
+ theSpec2 = new InstrumentSpecification();
+ theSpec2.setTickSize(0.5);
+ theSpec2.setTickValue(25.0);
+ theSpec2.setId(2L);
+
+ }
+
+ @Test
+ public void testSingularInstrument()
+ {
+ OrderExecutionEvent myEvent = new OrderExecutionEvent();
+ myEvent.setEventTimeStamp(new TimeStamp(0L));
+ myEvent.setPrice(101.0);
+ myEvent.setQuantity(100.0);
+ Order myOrder = new Order();
+ myOrder.setOrderSide(OrderSide.BUY);
+ myOrder.setOrderType(OrderType.LIMIT);
+ myOrder.setQuantity(100.0);
+ myOrder.setInstrumentSpecification(theSpec1);
+ theLogger.log(myOrder,myEvent);
+ Quote myQuote = new Quote();
+ myQuote.setTimeStamp(new TimeStamp(1L));
+ myQuote.setInstrumentSpecification(theSpec1);
+ myQuote.setBidPrice(100);
+ myQuote.setAskPrice(101);
+ // check what we have so far.
+ System.out.println(theCommonStream.toString());
+ theLogger.log(myQuote);
+ System.out.println(thePnlStream.toString());
+ assertEquals("1;;PNL;-100\n", thePnlStream.toString());
+ myQuote.setTimeStamp(new TimeStamp(2L));
+ myQuote.setBidPrice(101);
+ myQuote.setAskPrice(102);
+ theLogger.log(myQuote);
+ System.out.println(thePnlStream.toString());
+ assertEquals("1;;PNL;-100\n2;;PNL;0\n", thePnlStream.toString());
+
+ // liquidate .... and track a quote.
+
+
+
+ }
+
+}

Added: activequant-base/trunk/activequant-framework/src/test/java/org/activequant/util/log/PnlLoggerTest.java
===================================================================
--- activequant-base/trunk/activequant-framework/src/test/java/org/activequant/util/log/PnlLoggerTest.java                        (rev 0)
+++ activequant-base/trunk/activequant-framework/src/test/java/org/activequant/util/log/PnlLoggerTest.java 2009-10-05 11:38:59 UTC (rev 480)
@@ -0,0 +1,99 @@
+package org.activequant.util.log;
+
+import static org.junit.Assert.assertEquals;
+
+import org.activequant.core.domainmodel.InstrumentSpecification;
+import org.activequant.core.domainmodel.account.Order;
+import org.activequant.core.domainmodel.data.Quote;
+import org.activequant.core.domainmodel.events.OrderExecutionEvent;
+import org.activequant.core.types.OrderSide;
+import org.activequant.core.types.OrderType;
+import org.activequant.core.types.TimeStamp;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PnlLoggerTest {
+
+ private PnlLogger theLogger;
+ private InstrumentSpecification theSpec1, theSpec2;  
+
+ @Before
+ public void setUp() throws Exception {
+ theLogger = new PnlLogger();
+ theSpec1 = new InstrumentSpecification();
+ // assuming a plain ETF or stock.
+ theSpec1.setTickSize(1.0);
+ theSpec1.setTickValue(1.0);
+ theSpec1.setId(1L);
+ // assuming a dax.
+ theSpec2 = new InstrumentSpecification();
+ theSpec2.setTickSize(0.5);
+ theSpec2.setTickValue(12.5);
+ theSpec2.setId(2L);
+
+ }
+
+ @Test
+ public void testSingularInstrument()
+ {
+ OrderExecutionEvent myEvent = new OrderExecutionEvent();
+ myEvent.setEventTimeStamp(new TimeStamp(0L));
+ myEvent.setPrice(101.0);
+ myEvent.setQuantity(100.0);
+ Order myOrder = new Order();
+ myOrder.setOrderSide(OrderSide.BUY);
+ myOrder.setOrderType(OrderType.LIMIT);
+ myOrder.setQuantity(100.0);
+ myOrder.setInstrumentSpecification(theSpec1);
+ theLogger.log(myOrder,myEvent);
+ Quote myQuote = new Quote();
+ myQuote.setTimeStamp(new TimeStamp(1L));
+ myQuote.setInstrumentSpecification(theSpec1);
+ myQuote.setBidPrice(100);
+ myQuote.setAskPrice(101);
+ theLogger.log(myQuote);
+
+ assertEquals(1, theLogger.getPnlValueSeries().size());
+
+ myQuote.setTimeStamp(new TimeStamp(2L));
+ myQuote.setBidPrice(101);
+ myQuote.setAskPrice(102);
+ theLogger.log(myQuote);
+
+ assertEquals(2, theLogger.getPnlValueSeries().size());
+ assertEquals(0.0, theLogger.getPnlValueSeries().get(1).getValue(), 0.0001);
+ }
+
+
+ @Test
+ public void testSingularInstrumentBig()
+ {
+ OrderExecutionEvent myEvent = new OrderExecutionEvent();
+ myEvent.setEventTimeStamp(new TimeStamp(0L));
+ myEvent.setPrice(100.0);
+ myEvent.setQuantity(100.0);
+ Order myOrder = new Order();
+ myOrder.setOrderSide(OrderSide.SELL);
+ myOrder.setOrderType(OrderType.LIMIT);
+ myOrder.setQuantity(100.0);
+ myOrder.setInstrumentSpecification(theSpec2);
+ theLogger.log(myOrder,myEvent);
+ Quote myQuote = new Quote();
+ myQuote.setTimeStamp(new TimeStamp(1L));
+ myQuote.setInstrumentSpecification(theSpec2);
+ myQuote.setBidPrice(100);
+ myQuote.setAskPrice(101);
+ theLogger.log(myQuote);
+
+ assertEquals(1, theLogger.getPnlValueSeries().size());
+
+ myQuote.setTimeStamp(new TimeStamp(2L));
+ myQuote.setBidPrice(101);
+ myQuote.setAskPrice(102);
+ theLogger.log(myQuote);
+
+ assertEquals(2, theLogger.getPnlValueSeries().size());
+ assertEquals(2 * 25 * 100, theLogger.getPnlValueSeries().get(1).getValue(), 0.0001);
+ }
+
+}

_______________________________________________
ccapi mailing list
ccapi@...
http://activestocks.de/cgi-bin/mailman/listinfo/ccapi

Re: repo: sandbox, rev: r480 - in activequant-base/trunk/activequant-framework/src: main/java/org/activequant/broker main/java/org/activequant/container/report main/java/org/activequant/container/report/statistics main/java/org/activequant/core/domainmodel/data main/java/org/activequant/util main/java/org/activequant/util/log main/java/org/activequant/util/tools test/java/org/activequant/util test/java/org/activequant/util/log

by H. Canterburry :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Now...this is good stuff to have in a forum! :-)
-HC

Re: repo: sandbox, rev: r480 - in activequant-base/trunk/activequant-framework/src: main/java/org/activequant/broker main/java/org/activequant/container/report main/java/org/activequant/container/report/statistics main/java/org/activequant/core/domainmodel/data main/java/org/activequant/util main/java/org/activequant/util/log main/java/org/activequant/util/tools test/java/org/activequant/util test/java/org/activequant/util/log

by H. Canterburry :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Now...this is good stuff to have in a forum! :-)
-HC

Re: repo: sandbox, rev: r480 - in activequant-base/trunk/activequant-framework/src: main/java/org/activequant/broker main/java/org/activequant/container/report main/java/org/activequant/container/report/statistics main/java/org/activequant/core/domainmodel/data main/java/org/activequant/util main/java/org/activequant/util/log main/java/org/activequant/util/tools test/java/org/activequant/util test/java/org/activequant/util/log

by H. Canterburry :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Now...this is good stuff to have in a forum! :-)
-HC