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

178
LINES

< > BotCompany Repo | #1036199 // Corridor [backup]

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

Libraryless. Click here for Pure Java version (10557L/53K).

set flag Reparse.

sclass Corridor {
  record noeq Position(/*settable*/ double openingPrice, /*settable*/ double direction) {
    /*settable*/ double closingPrice = Double.NaN;
    
    bool closed() { ret !isNaN(closingPrice); }
    S type() { ret trading_directionToPositionType(direction); }
    
    double profitAtPrice(double price) {
      ret (price-openingPrice)*direction;
    }
    
    double profit() {
      ret profitAtPrice(closed() ? closingPrice : currentPrice());
    }
    
    void close {
      if (closed()) fail("Can't close again");
      openPositions.remove(this);
      closingPrice = currentPrice();
      closedPositions.add(this);
      realizedProfit += profit();
    }
    
    toString {
      ret renderFunctionCall(
        spaceCombine(
          closed() ? "Closed" : null,
          type()
        ),
        openingPrice,
        "profit=" + profit());
    }
  }
      
  record noeq Threshold(/*settable*/ double price, /*settable*/ double direction, Runnable action) {
    void trigger {
      print("Triggered at " + price + " " + direction + ": " + action); 
      callF(action);
    }
  }
  
  settable double epsilon = 0.001;
  settable double ladderStep = 1;
  gettable double currentPrice = 0;
  
  gettable double lastDirection;
  gettable double realizedProfit;
  new L<Loop> loops;
  new TreeMultiMap<Double, Threshold> thresholds;
  new LinkedHashSet<Position> openPositions;
  new L<Position> closedPositions;
  
  record noeq Loop(/*settable*/ double startingPrice, /*settable*/ double direction) {
    Position position;
    Loop successor;
    
    class Open is Runnable {
      run {
        if (position != null && !position.closed())
          fail("Trying to re-open position: " + this);
          
        print("Opening position at " + currentPrice() + " by loop " + this);
        position = openPosition(direction);
        if (successor == null)
          successor = new Loop(startingPrice+ladderStep, direction).init();
      }
      
      toString { ret spaceCombine("Open", startingPrice, direction); }
    }
    
    class Close is Runnable {
      run {
        if (position != null) {
          print("Closing position at " + currentPrice() + " by loop " + this);
          position.close();
        }
      }
      
      toString { ret spaceCombine("Close", startingPrice, direction); }
    }
    
    selfType init() {
      loops.add(this);
      addThreshold(startingPrice, -direction, new Open);
      addThreshold(startingPrice+ladderStep, direction, new Close);
      
      this;
    }
    
    toString {
      ret formatRecordVars("Loop",
        +startingPrice,
        +direction, 
        +position,
        succ := successor == null ?: "t"
      );
    }
  }
  
  Position openPosition(double direction) {
    ret addAndReturn(openPositions, new Position(currentPrice(), direction));
  }
  
  Threshold addThreshold(double price, double direction, Runnable action) {
    var t = new Threshold(price, direction, action);
    thresholds.put(t.price, t);
    bool triggered = (lastDirection == 0 || lastDirection == direction) && absDiff(currentPrice, price) < epsilon;
    printVars addThreshold(+currentPrice, +price, +direction, +lastDirection, +triggered);
    if (triggered)
      t.trigger();
    ret t;
  }
  
  void start {
    double price = currentPrice();
    print("Starting CORRIDOR at " + price + " +/- " + ladderStep);
    lastDirection = 0;
    new Loop(price, 1).init();
    new Loop(price, -1).init();
  }
  
  selfType currentPrice aka price(double price) {
    double oldPrice = currentPrice;
    if (oldPrice == price) this;
    
    currentPrice = price;
    int direction = sign(price-oldPrice);
    lastDirection = direction;
    NavigableMap<Double, L<Threshold>> map = thresholds.innerMap();
    map = direction > 0
      ? map.subMap(oldPrice, false, price, true)
      : map.subMap(price, true, oldPrice, false);
    var keys = keys(map);
    LL<Threshold> thresholdsCrossed = valuesList(map);
    if (direction < 0)
      reverseInPlace(thresholdsCrossed);
    
    new L<Threshold> toExecute;
    for (actions : thresholdsCrossed)
      for (t : actions)
        if (t.direction == direction)
          toExecute.add(t);

    printWithPrecedingNL(commaCombine(
      "New price: " + currentPrice,
      "direction: " + direction,
      "Thresholds crossed: " + keys,
      n2(toExecute, "trigger")));
    
    for (t : toExecute) t.trigger();
    
    this;
  }
  
  double unrealizedProfit() {
    ret doubleSum(map(openPositions, ->.profit()));
  }
  
  double profit() {
    ret realizedProfit+unrealizedProfit();
  }
  
  LS status() {
    double up = unrealizedProfit();
    ret ll(
      "Profit: " + realizedProfit+up,
      "Realized profit: " + realizedProfit + " from " + n2(closedPositions, "closed position"),
      "Unrealized profit: " + up + " in " + n2(openPositions, "open position"),
      //n2(loops, "loop"),
      //n2(keysSize(thresholds), "threshold"),
      //n2(l(thresholds), "threshold action"),
    );
  }
  
  toString { ret commaCombine(status()); }
}

Author comment

Began life as a copy of #1036196

download  show line numbers  debug dex  old transpilations   

Travelled to 2 computer(s): mqqgnosmbjvj, wnsclhtenguj

No comments. add comment

Snippet ID: #1036199
Snippet name: Corridor [backup]
Eternal ID of this version: #1036199/1
Text MD5: df720143d023644cd40c4dc87b1dccde
Transpilation MD5: 3ae729a21689ec51e14d9fa44bfcac8d
Author: stefan
Category: javax / gazelle 22
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-10-17 01:09:41
Source code size: 5275 bytes / 178 lines
Pitched / IR pitched: No / No
Views / Downloads: 59 / 79
Referenced in: [show references]