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

149
LINES

< > BotCompany Repo | #1036148 // MPM2 - Trading Bot v2

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

Transpiled version (11080L) is out of date.

set flag Reparse.
replace real with double.
replace Real with Double.
replace price with float.

srecord noeq MPM2(price[] ticker, long[] timestamps) {
  // How much percentual slippage we have for each position on
  // average plus the fees for the position.
  // Obviously dependent on the market (trading site) we are using.
  srecord Market(real adversity) {}
  
  srecord Position(real openingTime, real direction) {}
  
  record ClosedPosition(Position p, real closingTime) {
    settable Ticker ticker;
    settable real profit;
    
    MPM2 mpm() { ret MPM2.this; }
    
    real openingPrice() { ret MPM2.this.ticker(p.openingTime); }
    real closingPrice() { ret MPM2.this.ticker(closingTime); }
  }
  
  srecord Juicer(real lossTolerance, real pullback) {}

  abstract sclass Eye {
    abstract real adviseDirection(Ticker ticker);
  }
  
  // only the first length items in data and timestamps are looked at
  srecord noeq Ticker(price[] data, long[] timestamps, int length, long currentTime) {
    real currentPrice() { ret data[length-1]; }
    
    Real lookback(real time) {
      int index = binarySearch_insertionPoint(wrapLongArrayAsList(timestamps), lceil(currentTime-time));
      ret index >= 0 ? (real) data[index] : null;
    }
  }
  
  sclass LiveTicker extends Ticker {
    void add(price value, long timestamp) {
      data = addToArrayWithDoublingStrategy(data, length, value);
      timestamps = addToArrayWithDoublingStrategy(timestamps, length, timestamp); 
      length++;
    }
  }
  
  Ticker ticker() { ret new Ticker(ticker, timestamps, l(timestamps), last(timestamps)); }

  srecord SimpleEye(real time, real minMove) extends Eye {
    real adviseDirection(Ticker ticker) {
      Real currentPrice = ticker.currentPrice();
      if (currentPrice == null) ret 0;
      Real before = ticker.lookback(time);
      if (before == null) ret 0;
      real move = currentPrice/before*100-100;
      if (abs(move) >= minMove) ret (real) sign(move);
      ret 0;
    }
  }

  real ticker(real time) { ret ticker[iceil(time)]; }

  real openingPrice(Position p) { ret ticker(p.openingTime); }

  // all "profit" functions return a positive or negative percent value
  real profit(Position p, real time, Market m) {
    ret (ticker(time)/openingPrice(p)*100-100)*p.direction - m.adversity;
  }

  Real closingTime(Position p, Juicer j, Market m) {
    int time = iceil(p.openingTime);
    real openingPrice = ticker(time);
    real crest = -infinity();
    while (time < ticker.length-1) {
      real profit = profit(p, time, m);
      crest = max(crest, profit);
      if (profit < (profit < 0 ? -j.lossTolerance : crest-j.pullback))
        ret (real) time;
      ++time;
    }
    null;
  }

  Real profit(Position p, Juicer j, Market m) {
    Real closingTime = closingTime(p, j, m);
    ret closingTime == null ? null : profit(p, closingTime, m);
  }

  // How profitable is it to open a position of any direction
  // at a certain point in time?
  Real profitability(real time, Juicer j, Market m) {
    ret maxAllowingNull(
      profit(new Position(time, -1), j, m), 
      profit(new Position(time,  1), j, m));
  }
  
  // eye can be null, then we just test the juicer
  record noeq Backtest(Eye eye, Juicer j, Market m) extends Convergent<Real> {
    Iterator<Int> openingTimes = new WeightlessShuffledIterator<Int>(intRangeList(ticker.length));
    
    new Average profitPerPosition;
    // TODO new Average averageHoldTime;
    new Average positionsOpenedPercentage;
    
    // percentage of positions closed before reaching the end of the ticker "tape"
    new Average positionsClosedPercentage;
    
    new L<ClosedPosition> closedPositions;
    
    *(Juicer *j, Market *m) {}
    
    // internal, don't call from outside. Use Convergent/Iterator methods
    void step {
      if (!openingTimes.hasNext())
        ret with done = true;
        
      int openingTime = openingTimes.next();
      
      Real profit = null;
      ClosedPosition closedPosition = null;
      
      if (eye == null) // Test only juicer
        profit = profitability(openingTime, j, m);
      else {
        // Test eye + juicer
        real direction = eye.adviseDirection(new Ticker(ticker, timestamps, openingTime, timestamps[openingTime]));
        positionsOpenedPercentage.addSample(direction != 0 ? 100 : 0);
        if (direction != 0) {
          Position position = new Position(openingTime, direction);
          Real closingTime = closingTime(position, j, m);
          if (closingTime != null) {
            profit = profit(position, closingTime, m);
            closedPosition = new ClosedPosition(position, closingTime).ticker(ticker()).profit(profit);
            closedPositions.add(closedPosition);
          }
        }
      }
      
      positionsClosedPercentage.addSample(profit != null ? 100 : 0);
      if (profit != null) {
        profitPerPosition.addSample(profit);
        //averageHoldTime.addSample(TODO);
      } else // Profit for unclosed positions = 0
        profitPerPosition.addSample(0);
      value = profitPerPosition!;
    }
  }
}

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1036148
Snippet name: MPM2 - Trading Bot v2
Eternal ID of this version: #1036148/72
Text MD5: 013c41bc0ed1e77ae089892172dc2d5a
Author: stefan
Category: javax / trading bot
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-10-04 13:46:26
Source code size: 5250 bytes / 149 lines
Pitched / IR pitched: No / No
Views / Downloads: 212 / 639
Version history: 71 change(s)
Referenced in: #1003674 - Standard Classes + Interfaces (LIVE continued in #1034167)
#1036152 - MPM2 backup untested
#1036164 - MPM3 - Trading Bot v3