001 /**
002 * Copyright 2007 Mike Kroutikov.
003 *
004 * This program is free software; you can redistribute it and/or modify
005 * it under the terms of the Lesser GNU General Public License as
006 * published by the Free Software Foundation; either version 3 of
007 * the License, or (at your option) any later version.
008 *
009 * This program is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012 * Lesser GNU General Public License for more details.
013 *
014 * You should have received a copy of the Lesser GNU General Public License
015 * along with this program. If not, see <http://www.gnu.org/licenses/>.
016 */
017
018 package org.otfeed.protocol.request;
019
020 import org.otfeed.command.VolumeStyleEnum;
021 import org.otfeed.event.ICompletionDelegate;
022 import org.otfeed.event.IDataDelegate;
023 import org.otfeed.event.OTBBO;
024 import org.otfeed.event.OTMMQuote;
025 import org.otfeed.event.OTQuote;
026 import org.otfeed.event.OTTrade;
027 import org.otfeed.protocol.CommandEnum;
028 import org.otfeed.protocol.DataEnum;
029 import org.otfeed.protocol.ProtocolException;
030
031 import org.otfeed.protocol.request.quote.QuoteReader;
032
033 import java.nio.ByteBuffer;
034
035 import java.util.Date;
036 import java.util.Map;
037 import java.util.HashMap;
038
039 /**
040 * Request to receive historical quote events.
041 */
042 public final class HistTicksRequest extends AbstractSessionRequest {
043
044 private final String exchangeCode;
045 private final String symbolCode;
046 private final Date startDate;
047 private final Date endDate;
048 private final VolumeStyleEnum volumeStyle;
049 private final int mask;
050
051 public String getExchangeCode() { return exchangeCode; }
052 public String getSymbolCode() { return symbolCode; }
053 public Date getStartDate() { return startDate; }
054 public Date getEndDate() { return endDate; }
055 public VolumeStyleEnum getVolumeStyle() { return volumeStyle; }
056
057 private final Map<Integer,QuoteReader> map = new HashMap<Integer,QuoteReader>();
058
059 public HistTicksRequest(int requestId,
060 String exchangeCode,
061 String symbolCode,
062 Date startDate,
063 Date endDate,
064 VolumeStyleEnum volumeStyle,
065 IDataDelegate<OTQuote> quoteDelegate,
066 IDataDelegate<OTTrade> tradeDelegate,
067 IDataDelegate<OTMMQuote> mmQuoteDelegate,
068 IDataDelegate<OTBBO> bboDelegate,
069 ICompletionDelegate completionDelegate) {
070
071 super(CommandEnum.REQUEST_HIST_TICKS,
072 requestId, completionDelegate);
073
074 Check.notNull(exchangeCode, "exchangeCode");
075 Check.notNull(symbolCode, "symbolCode");
076 Check.notNull(startDate, "startDate");
077 Check.notNull(endDate, "endDate");
078 Check.notNull(volumeStyle, "volumeStyle");
079
080 this.exchangeCode = exchangeCode;
081 this.symbolCode = symbolCode;
082 this.startDate = startDate;
083 this.endDate = endDate;
084 this.volumeStyle = volumeStyle;
085
086 int mask = 0;
087 if(quoteDelegate != null) {
088 QuoteReader rdr = QuoteReader.quoteReader(quoteDelegate);
089 map.put(rdr.type.code, rdr);
090 mask |= rdr.mask;
091 }
092 if(tradeDelegate != null) {
093 QuoteReader rdr = QuoteReader.tradeReader(tradeDelegate);
094 map.put(rdr.type.code, rdr);
095 mask |= rdr.mask;
096 }
097 if(mmQuoteDelegate != null) {
098 QuoteReader rdr = QuoteReader.mmQuoteReader(mmQuoteDelegate);
099 map.put(rdr.type.code, rdr);
100 mask |= rdr.mask;
101 }
102 if(bboDelegate != null) {
103 // TODO: bbo events impossible here?
104 QuoteReader rdr = QuoteReader.bboReader(bboDelegate);
105 map.put(rdr.type.code, rdr);
106 mask |= rdr.mask;
107 }
108 if(mask == 0) {
109 throw new IllegalArgumentException("must set at least one quote event delegate");
110 }
111
112 switch(volumeStyle) {
113 case INDIVIDUAL:
114 mask |= VolumeStyleEnum.INDIVIDUAL_VOLUME_FLAG;
115 break;
116 case COMPOUND:
117 break;
118 default:
119 throw new IllegalArgumentException("unrecognized volumeStyle: " + volumeStyle);
120 }
121 this.mask = mask;
122 }
123
124 @Override
125 public void writeRequest(ByteBuffer out) {
126 super.writeRequest(out);
127
128 Util.writeString(out, exchangeCode, 15);
129 Util.writeString(out, symbolCode, 15);
130 Util.writeDate(out, startDate);
131 Util.writeDate(out, endDate);
132 out.putInt(mask);
133 }
134
135 @Override
136 public JobStatus handleMessage(Header header, ByteBuffer in) {
137
138 if(header.getCommand() != CommandEnum.REQUEST_HIST_DATA) {
139 throw new ProtocolException("unexpected command: "
140 + header.getCommand(), in);
141 }
142
143 int count = in.getInt();
144
145 while( count -- > 0) {
146
147 int typeCode = in.get();
148 if(typeCode == DataEnum.EOD.code) {
149 return JobStatus.FINISHED;
150 }
151
152 QuoteReader reader = map.get(typeCode);
153 if(reader == null) {
154 throw new ProtocolException("unrecognized type: " + typeCode, in);
155 }
156
157 reader.read(header, in);
158 }
159
160 return JobStatus.ACTIVE;
161 }
162
163 @Override
164 public final CommandEnum getCancelCommand() {
165 return CommandEnum.CANCEL_HIST_DATA; // fixme??
166 }
167 }