Skip to content
Marco Terzer edited this page Aug 30, 2015 · 21 revisions

Initial Thoughts

  • Connection Schedules for both Daily and Weekly simultaneously. I want to be able to say: Trading between 17:05 and 17:00, Sunday to Friday.
  • Sequence Resets at Logon, Successful Logoff, and Daily (many venues requires Daily).
  • Metrics gathering: Queue times, Round trip latency, Messages/sec, etc.
  • Persistence: Chronicle etc. for storing messages in queues?
  • Configure to use Heartbeat (as per standard FIX) or TestRequest
  • Java 8 for all the lambda goodness
  • How do we feel about "bags of tags" over typed specific messages. I really don't find the typed messages that useful and they make it REALLY difficult to add custom tags, or modify standard messages in any way to accomodate 3rd parties who vary from the standard--which is pretty much everyone to some degree
  • Ability to readily switch on message types and tags:
  • Please, no more if (getMsgType().equals(...)) { ... }!
  • Perhaps use some way to convert message type to an integer for switching purposes?
  • Perhaps ability to register for specific MessageTypes so the dispatching can be done inside the engine instead of application code?
  • All this is much easier in Java 8 now
  • Fixed-widths possible for many fields such as sequence number, comp IDs, timestamps, etc.
  • Separate validation of wellformedness from content. QF conflates these two and it's rarely helpful
  • Listen for proper session status updates: created, disconnected; connected; logged off; logged on; ready for trading
  • Ability to associate arbitrary state with a session, given a lifespan (i.e. Forever vs While Connected vs While Logged On). I have just found myself wanting to be able to do it from time to time. I guess this could be handled with the lifecycle callbacks anyway?
  • Perhaps start by getting two clients to negotiate logon (ignoring compids, passwords, etc.) and then start heartbeating? Would be cool to get just that far to begin with.
Ordinals {
  private final ConcurrentMap<String, Integer> values = ;
  private final AtomicInteger next = new AtomicInteger(0);

  public int of(String s) {
    Objects.requireNotNull(s);
    return values.computeIfAbsent(s, _ -> next.getAndIncrement());
  }
}

MessageType {
  private static final Ordinals ordinals = new Ordinals();

  public static int ordinalOf(String messageType) {
    return ordinals.of(messageType);
  }
  
  public int ordinal() {
    return ordinal;
  }
}

Fix42MessageTypes {
  public static final int NewOrderSingle = MessageType.ordinalOf("D")
  public static final int ExecutionReport = MessageType.ordinalOf("8")
}

final int SomeCustomMessage = MessageType.ordinalOf("U1234");

Message {
    MessageType messageType();

    boolean isSet(Tag tag);

    String get(Tag tag);
    void get(Tag tag, Consumer<String> consumer);

    void set(Tag tag, String value);
    void set(Tag tag, Supplier<String> supplier);

    void copy(Tag tag, Message from);
}

message = ...;
switch (message.messageType().ordinal()) {
  case Fix42MessageTypes.NewOrderSingle:
    ...
    break;
  case Fix42MessageTypes.ExecutionReport:
    ...
    break;
  case SomeCustomMessage:
    ...
    break;
}

My 2c

public interface Message extends TagBag {
	MsgType msgType();
}
public interface TagBag {
    boolean isSet(FixTag tag);

    String getString(FixTag tag);
    void getString(FixTag tag, Consumer<? super String> consumer);
    long getInt(LongTag tag);
    void getInt(LongTag tag, IntConsumer consumer);
    long getLong(LongTag tag);
    void getLong(LongTag tag, LongConsumer consumer);
    double getDouble(DoubleTag tag);
    void getDouble(DoubleTag tag, DoubleConsumer consumer);
    <T> T getObject(ObjectTag<T> tag);
    <T> void getObject(ObjectTag<T> tag, Consumer<? super T> consumer);

    void setString(FixTag tag, String value);
    void setString(FixTag tag, Supplier<? extends String> supplier);
    void setLong(LongTag tag, long value);
    void setLong(LongTag tag, LongSupplier supplier);
    <T> void setObject(ObjectTag<T> tag, T value);
    <T> void setObject(ObjectTag<T> tag, Supplier<? extends T> supplier);

    void copy(FixTag tag, TagBag from);
}
  • Another approach (maybe underneath or in addition to above)
public interface TagStream {
	/**
	 * If a next tag exists, passes it with the associated value to the given consumer, returning {@code true}; else
	 * returns {@code false}.
	 *
	 * @param consumer
	 *            The consumer for the tag/value if found
	 * @return {@code false} if no remaining tag existed upon entry to this method, else {@code true}.
	 * @throws NullPointerException
	 *             if the specified consumer is null
	 */
	boolean tryNextTag(TagValueConsumer consumer);
}
public interface TagValueConsumer {
	void accept(IntTag tag, int value);
	void accept(LongTag tag, long value);
	void accept(DoubleTag tag, double value);
	void accept(FixTag tag, CharSequence value);
}
Clone this wiki locally