Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

322
LINES

< > BotCompany Repo | #1036138 // TickerSequence - sequence of ticker values (prices) with timestamps

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (16512L/94K).

persistable sclass TickerSequence is IntSize {
  settable S market; // e.g. "TRBUSDT"
  
  // in case the sequence is digitized
  settable PriceCells priceCells;
  
  // are we live?
  settable bool live;
  
  // Is the data incomplete (still loading)?
  settable bool loading;
  
  ILongBuffer timestamps = new SynchronizedLongBuffer;
  IDoubleBuffer prices = new SynchronizedFloatBufferPresentingAsDoubles;
  
  // timestamp of last ticker event even though price may not
  // have changed
  settable long lastTickerEvent;
  
  settable double epsilon = 1e-6;
  
  event pricePointAdded(long timestamp);
  
  *(S *market) {}
  
  synchronized void addIfPriceChanged(double price, long timestamp) {
    lastTickerEvent = max(lastTickerEvent, timestamp);
    if (isEmpty() || differentByEpsilonRatio(prices.last(), price, epsilon))
      add(price, timestamp);
  }
  
  synchronized void add aka addPrice(double price, long timestamp) {
    lastTickerEvent = max(lastTickerEvent, timestamp);
    timestamps.add(timestamp);
    prices.add(price);
    pricePointAdded(timestamp);
  }
  
  synchronized void add(double[] prices, long[] timestamps) {
    assertEquals(l(prices), l(timestamps));
    if (empty(prices)) ret;
    
    // TODO: call pricePointAdded?
    this.prices.addAll(asList(prices));
    this.timestamps.addAll(asList(timestamps));
    lastTickerEvent = max(lastTickerEvent, endTime());
  }
  
  synchronized void add(TickerSequence ticker) {
    add(ticker.prices.toArray(), ticker.timestamps.toArray());
  }
  
  synchronized toString {
    ret commaCombine(
      spaceCombine(
        "Ticker",
        market,
        priceCells == null ?: roundBracket(priceCells),
      ),
      formatDays(duration()),
      n2(l(prices), "price point"),
      timeRange()
    );
  }
  
  synchronized TickerSequence subSequence(int start, int end default size()) {
    new TickerSequence s;
    s.market(market);
    s.add(
      subDoubleArray(prices.toArray(), start, end),
      subArray(timestamps.toArray(), start, end));
    ret s;
  }
  
  synchronized TickerSequence cutOffAfterSeconds(double seconds) {
    int idx = indexOfTimestamp(startTime()+secondsToMS(seconds));
    ret subSequence(0, idx);
  }

  TickerSequence takeFirstDays(double days) {
    ret cutOffAfterSeconds(daysToSeconds(days));
  }

  TickerSequence takeLastDays(double days) {
    int idx = indexOfTimestamp(endTime()-daysToMS(days));
    ret subSequence(idx);
  }

  synchronized TickerSequence subSequenceByTimestamps(long from, long to) {
    int idx1 = indexOfTimestamp(from);
    int idx2 = indexOfTimestamp(to);
    ret subSequence(idx1, idx2);
  }
  
  synchronized TickerSequence subSequenceFromTimestamp(long from) {
    ret subSequence(indexOfTimestamp(from));
  }
  
  synchronized int indexOfTimestamp(double ts) {
    ret binarySearch_insertionPoint(timestamps.asVirtualList(), lround(ts));
  }
  
  synchronized long nextTimestamp(double ts) {
    ret getTimestamp(indexOfTimestamp(ts)+1);
  }
  
  synchronized double priceAtTimestamp(double ts) {
    ret getPrice(indexOfTimestamp(ts));
  }

  public int size() { ret l(prices); }
  public bool isEmpty() { ret size() == 0; }
  
  synchronized TimestampRange timeRange() {
    ret isEmpty() ? null : TimestampRange(startTime(), endTime());
  }
  
  Duration duration() {
    ret main duration(timeRange());
  }
  
  synchronized long startTime() { ret empty(timestamps) ? 0 : first(timestamps); }
  synchronized long endTime() { ret empty(timestamps) ? 0 : last(timestamps); }
  
  synchronized double getPrice(int i) { ret prices.get(clampToLength(size(), i)); }
  synchronized long getTimestamp(int i) { ret timestamps.get(clampToLength(size(), i)); }
  
  synchronized TickerSequence removePlateaus() {
    new TickerSequence seq;
    seq.market(market);
    int n = size();
    
    for i to n: {
      var value = getPrice(i);
      seq.prices.add(value);
      seq.timestamps.add(getTimestamp(i));
      
      while (i+1 < n && getPrice(i+1) == value) ++i;
    }
    
    ret seq.trimToSize();
  }
  
  synchronized TickerSequence alignTimestamps(int interval) {
    new TickerSequence seq;
    seq.market(market);
    int n = size();
    
    for i to n: {
      var value = getPrice(i);
      long time = roundDownTo(interval, getTimestamp(i));
      if (time != seq.endTime())
        seq.addIfPriceChanged(value, time);
    }
      
    ret seq.trimToSize();
  }
  
  selfType trimToSize() {
    prices.trimToSize();
    timestamps.trimToSize();
    this;
  }
  
  double minPrice() { ret doubleMin(prices.toArray()); }
  double maxPrice() { ret doubleMax(prices.toArray()); }
  
  synchronized double firstPrice() { ret empty(prices) ? Double.NaN : prices.first(); }
  synchronized double lastPrice() { ret empty(prices) ? Double.NaN : prices.last(); }
  
  synchronized TickerPoint lastPoint() {
    ret new TickerPoint(this, endTime());
  }
  
  static Pattern reBestAsk = regexp("\"bestAsk\":([0-9\\.]+)");
  static Pattern reSystemTime = regexp("\"systemTime\":(\\d+)");
  
  // parse line from a .ticker file
  synchronized void addJSONLine_fast(S line) {
    long time = toLong(regexpFirstGroup(reSystemTime, line));
    if (time > lastTickerEvent) {
      double price = toDouble(regexpFirstGroup(reBestAsk, line));
      addIfPriceChanged(price, time);
    }
  }
  
  swappable void addJSONLine(S line) {
    addJSONLine_slow(line);
  }
  
  synchronized void addJSONLine_slow(S line) {
    Map data = parseJSONMap(line);
    double price = toDouble(data.get("bestAsk"));
    long time = toLong(data.get("systemTime"));
    if (time > lastTickerEvent) 
      addIfPriceChanged(price, time);
  }
  
  UpDownSequence toUpDownSequence aka upDownSequence(PriceCells cells default priceCells) {
    if (cells == null) null;
    var dig = digitize(new PriceDigitizer(cells));
    L<Int> cellNumbers = dig.roundedCellNumbers();
    ret UpDownSequence.fromInts(cellNumbers);
  }
  
  TickerSequence digitizeToPercent(double basePrice default firstPrice(), double cellSizeInPercent) {
    if (isEmpty()) this;
    ret digitize(geometricPriceDigitizer(basePrice, cellSizeInPercent));
  }
  
  TickerSequence digitize(PriceDigitizer digitizer) {
    new TickerSequence seq;
    seq.market(market);
    seq.priceCells(digitizer.priceCells());
    int n = size();
    
    for i to n: {
      seq.addIfPriceChanged(digitizer.digitize(getPrice(i)), getTimestamp(i));
    }
    
    ret seq.trimToSize();
  }
  
  L<PricePoint> pricePoints() {
    ret listFromFunction getPricePoint(size());
  }
  
  PricePoint getPricePoint(int idx) {
    ret new PricePoint(timestamps.get(idx), prices.get(idx));
  }
  
  L<Int> roundedCellNumbers() {
    ret map iround(cellNumbers());
  }
  
  L<Double> cellNumbers() {
    if (priceCells == null) null;
    int n = size();
    DoubleBuffer buf = new(n);
    for i to n:
      buf.add(priceCells.toCellNumber(getPrice(i)));
    ret buf.asVirtualList();
  }
  
  TickerSequence toCellNumbers() {
    if (priceCells == null) null;
    new TickerSequence seq;
    seq.market(market + " cell numbers " + roundBracket(priceCells));
    int n = size();
    
    for i to n:
      seq.add(priceCells.toCellNumber(getPrice(i)), getTimestamp(i));

    ret seq.trimToSize();
  }
  
  void dropLastPricePoint() {
    if (isEmpty()) ret;
    prices.popLast();
    timestamps.popLast();
    lastTickerEvent = endTime();
  }
  
  selfType marketIfEmpty(S market) {
    if (empty(this.market)) market(market);
    this;
  }
  
  selfType legacyCompact() {
    if (!prices instanceof SynchronizedFloatBufferPresentingAsDoubles)
      prices = new SynchronizedFloatBufferPresentingAsDoubles(prices.toArray());
    this;
  }
  
  // msUnit = how many milliseconds to group into one
  bool compactTimestamps(long msUnit default 20) {
    if (!timestamps instanceof SynchronizedLongBufferStoredAsLinearInts) {
      timestamps = new SynchronizedLongBufferStoredAsLinearInts(roundDownTo(msUnit, startTime()), msUnit, timestamps);
      true;
    }
    false;
  }
  
  double averageTimeStep() {
    ret doubleRatio(endTime()-startTime(), size()-1);
  }
  
  public void write(ByteHead head) {
    head.writeString(market);
    SynchronizedLongBufferStoredAsLinearInts timestamps = cast this.timestamps;
    head.writeLong(timestamps.base);
    head.writeLong(timestamps.factor);
    
    int n = size();
    head.writeInt(n);

    for i to n: {
      head.writeInt(timestamps.getRaw(i));
      head.writeFloat((float) prices.get(i));
    }
  }
  
  static TickerSequence read(ByteHead head) {
    new TickerSequence t;
    t.market = head.readString();
    if (head.eof()) null;
    long base = head.readLong();
    long factor = head.readLong();
    //printVars(market := t.market, +base, +factor);
    SynchronizedLongBufferStoredAsLinearInts timestamps = new(base, factor);
    t.timestamps = timestamps;
    
    int n = head.readInt();
    for i to n: {
      int time = head.readInt();
      if (head.eof()) break;
      timestamps.addRaw(time);
      t.prices.add(head.readFloat());
    }
    ret t;
  }
}

download  show line numbers  debug dex  old transpilations   

Travelled to 3 computer(s): elmgxqgtpvxh, mqqgnosmbjvj, wnsclhtenguj

No comments. add comment

Snippet ID: #1036138
Snippet name: TickerSequence - sequence of ticker values (prices) with timestamps
Eternal ID of this version: #1036138/109
Text MD5: 21aa2ff13bea085f08e8efd9b245f403
Transpilation MD5: 8b31787800829f65d149ba36f7cf4e06
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-12-08 01:09:33
Source code size: 9408 bytes / 322 lines
Pitched / IR pitched: No / No
Views / Downloads: 249 / 864
Version history: 108 change(s)
Referenced in: [show references]