Package com.barchart.feed.base.provider

Source Code of com.barchart.feed.base.provider.UniBook

/**
* Copyright (C) 2011-2013 Barchart, Inc. <http://www.barchart.com/>
*
* All rights reserved. Licensed under the OSI BSD License.
*
* http://www.opensource.org/licenses/bsd-license.php
*/
package com.barchart.feed.base.provider;

import static com.barchart.feed.base.book.api.MarketBook.ENTRY_TOP;
import static com.barchart.feed.base.book.enums.UniBookResult.DISCARD;
import static com.barchart.feed.base.book.enums.UniBookResult.ERROR;
import static com.barchart.feed.base.book.enums.UniBookResult.NORMAL;
import static com.barchart.feed.base.book.enums.UniBookResult.TOP;
import static com.barchart.feed.base.provider.UniBookRing.CLUE_NONE;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.barchart.feed.api.model.data.Book;
import com.barchart.feed.api.model.meta.Instrument;
import com.barchart.feed.base.book.api.MarketDoBookEntry;
import com.barchart.feed.base.book.enums.UniBookResult;
import com.barchart.util.anno.NotThreadSafe;
import com.barchart.util.math.MathExtra;
import com.barchart.util.values.api.PriceValue;
import com.barchart.util.values.api.SizeValue;
import com.barchart.util.values.api.Value;
import com.barchart.util.values.provider.ValueFreezer;

@NotThreadSafe
// javaSize this = 8(obj) + 1(size) + 4(keyRef) + 4(bidsRef) + 4(asksRef) = 24
// javaSize deep = 136 * 2(asks+bids) + 24 (key) = 296
// javaSize = 320
class UniBook<V extends Value<V>> extends ValueFreezer<V> {

  @SuppressWarnings("unused")
  private static Logger log = LoggerFactory.getLogger(UniBook.class);

  protected final byte size;

  protected final PriceValue step;

  protected final UniBookRing bids;
  protected final UniBookRing asks;
 
  protected final Instrument instrument;

  public UniBook(final Instrument instrument, final Book.Type type,
      final SizeValue size, final PriceValue step)
          throws IllegalArgumentException, ArithmeticException {

    this.instrument = instrument;
   
    this.size = MathExtra.castLongToByte(size.asLong());

    this.step = step;

    this.bids = new UniBookRingBids(this, type);
    this.asks = new UniBookRingAsks(this, type);

    clear();

  }

  public final void clear() {
    // assume central price is zero
    bids.clear(-size);
    asks.clear(0);
  }

  // XXX returns null
  private final UniBookRing ringFor(final Book.Side side) {
    switch (side) {
    case BID:
      return bids;
    case ASK:
      return asks;
    default:
      return null;
    }
  }

  private final boolean isTopPlace(final MarketDoBookEntry entry) {
    return entry.place() == ENTRY_TOP;
  }

  private final boolean isValidEntryEnums(final MarketDoBookEntry entry) {

    if (entry == null) {
      return false;
    }

    switch (entry.act()) {
    case MODIFY:
    case REMOVE:
      break;
    default:
      return false;
    }

    switch (entry.side()) {
    case BID:
    case ASK:
      break;
    default:
      return false;
    }

    switch (entry.type()) {
    case DEFAULT:
    case IMPLIED:
      break;
    default:
      return false;
    }

    return true;

  }

  private final boolean isValidPlace(final MarketDoBookEntry entry) {
    final int place = entry.place();
    return ENTRY_TOP <= place && place <= size;
  }

  private final boolean isValidPrice(final MarketDoBookEntry entry) {
    return !entry.priceValue().isNull();
  }

  private final boolean isValidSize(final MarketDoBookEntry entry) {
    return !entry.sizeValue().isNull();
  }

  //

  // last updated entry signature
  private byte lastClue;
  private byte lastSide = Book.Side.NULL.ord;

  private final void saveLastClue(final int clue) {
    lastClue = MathExtra.castIntToByte(clue);
  }

  private void saveLastSide(final Book.Side side) {
    lastSide = side.ord;
  }

  /**
   * can return null; returns last changed entry how it looks after
   * modification;
   */
  protected final DefBookEntry lastEntry() {
    final Book.Side side = Book.Side.fromOrd(lastSide);
    final UniBookRing ring = ringFor(side);
    if (ring == null) {
      return null;
    }
    return ring.lastEntry(lastClue);
  }

  public final UniBookResult make(final MarketDoBookEntry entry) {

    make: if (isValidEntryEnums(entry)) {

      final UniBookResult result;

      switch (entry.act()) {
      case MODIFY:
        result = makeModify(entry);
        break;
      case REMOVE:
        result = makeRemove(entry);
        break;
      default:
        break make;
      }

      switch (result) {
      case TOP:
      case NORMAL:
        saveLastSide(entry.side());
        break;
      default:
        break;
      }

      return result;

    }

    return ERROR;

  }

  /**
   * covers "add", "change", "overlay"
   **/
  private final UniBookResult makeModify(final MarketDoBookEntry entry) {

    final UniBookRing ring = ringFor(entry.side());

    if (isValidPrice(entry)) {

      final int index = ring.index(entry.priceValue());

      // update top; based on place or price
      if (isTopPlace(entry) || ring.isNewTop(index)) {
        ring.setTop(index, entry);
        saveLastClue(ring.lastClue(index));
        return TOP;
      }

      // update in range
      if (ring.isValidIndex(index)) {
        ring.set(index, entry);
        saveLastClue(ring.lastClue(index));
        return NORMAL;
      }

      // can not update out of range
      return DISCARD;

    }

    // invalid book entry
    return ERROR;

  }

  /**
   * covers "clear", "delete", "remove"
   **/
  private final UniBookResult makeRemove(final MarketDoBookEntry entry)
      throws IllegalArgumentException {

    // expecting only NON meaningful size for delete operation
    if (isValidSize(entry)) {
      return ERROR;
    }

    final UniBookRing ring = ringFor(entry.side());

    // try to remove based on price
    if (isValidPrice(entry)) {

      final int index = ring.index(entry.priceValue());

      if (ring.isValidIndex(index)) {
        final boolean isOldTop = ring.isOldTop(index);
        ring.set(index, entry);
        saveLastClue(index);
        if (isOldTop) {
          return TOP;
        } else {
          return NORMAL;
        }
      } else {
        return DISCARD;
      }

    }

    // try to remove based on place
    if (isValidPlace(entry)) {

      final int clue = ring.placeRemove(entry);

      if (clue == CLUE_NONE) {
        // no such place
        return DISCARD;
      } else {
        saveLastClue(clue);
        if (isTopPlace(entry)) {
          return TOP;
        } else {
          return NORMAL;
        }
      }

    }

    // invalid book entry
    return ERROR;

  }

  /**
   * can return null
   **/
  protected final MarketDoBookEntry topFor(final Book.Side side) {

    final UniBookRing ring = ringFor(side);

    if (ring == null) {
      return null;
    }

    final int index = ring.indexTop();

    if (ring.isValidIndex(index)) {
      return ring.get(index);
    } else {
      return null;
    }

  }

  private final DefBookEntry nullEntry(final int index) {
    return new DefBookEntry(null, Book.Side.NULL, Book.Type.COMBINED,
        0, step.mult(index), null);
  }

  @Override
  public String toString() {

    final StringBuilder text = new StringBuilder(1024);

    for (int index = bids.head(); index <= bids.tail(); index++) {
      MarketDoBookEntry entry = bids.get(index);
      if (entry == null) {
        entry = nullEntry(index);
      }
      text.append(entry);
      text.append("\n");
    }

    final int gap = asks.head() - bids.tail();
    if (gap <= size) {
      for (int index = bids.tail() + 1; index < asks.head(); index++) {
        final DefBookEntry entry = nullEntry(index);
        text.append(entry);
        text.append("\n");
      }
    }

    for (int index = asks.head(); index <= asks.tail(); index++) {
      MarketDoBookEntry entry = asks.get(index);
      if (entry == null) {
        entry = nullEntry(index);
      }
      text.append(entry);
      text.append("\n");
    }

    return text.toString();

  }

  @Override
  public V freeze() {
    throw new UnsupportedOperationException();
  }

  @Override
  public boolean isFrozen() {
    return false;
  }

  protected final boolean isEmpty(final Book.Side side) {
    final UniBookRing ring = ringFor(side);
    if (ring == null) {
      return true;
    } else {
      return ring.isPlaceEmpty();
    }
  }

  @SuppressWarnings("unused")
  private final int ringGap() {
    return asks.head() - bids.tail();
  }

  // non null entries only, ordered by logical offset
  protected final DefBookEntry[] entriesFor(final Book.Side side) {
    final UniBookRing ring = ringFor(side);
    if (ring == null) {
      throw new IllegalArgumentException("invalid book side=" + side);
    } else {
      return ring.entries();
    }
  }

  protected final SizeValue[] sizesFor(final Book.Side side) {
    final UniBookRing ring = ringFor(side);
    if (ring == null) {
      throw new IllegalArgumentException("invalid book side=" + side);
    } else {
      return ring.sizes();
    }
  }

}
TOP

Related Classes of com.barchart.feed.base.provider.UniBook

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.