Libraryless. Click here for Pure Java version (30155L/190K).
concept CleanMoveStrategy extends G22TradingStrategy { // How clean the move must be settable double minCleanness = 2; // How profitable the move must be settable double minProfit = 0.5; // Factor for turning pullback into callback settable double callbackFactor = 1.5; // Max pullback of move settable double maxPullback = 1; // Price has to move at least this many percent for us to // recalculate the moves //settable double minChangeToReactTo = 0.1; // How often to start a new move analysis (seconds) settable double calcMovesEvery = 30; S fieldsToReset() { ret lines(ll(super.fieldsToReset(), [[currentMoves lastPriceReactedTo movesCalced]])); } // current short & long move settable L<LivePullbackToProfitAnalysis> currentMoves; //settable double lastPriceReactedTo; settable double movesCalced; persistable class Position extends G22TradingStrategy.Position { settable CallbackJuicer juicer; } srecord ProfitBeforeLeverageJuiceable(Position p) is Juiceable { public double juiceValue() { ret p.profitBeforeLeverage(); } } void price(double price) { if (currentPrice == price) ret; currentPrice = price; afterwards { afterStep(); change(); } // Close positions for (p : openPositions()) { if (p.juicer != null) { var signals = p.juicer.calculateCloseSignals(); var strongest = highestBy(signals, s -> s.strength()); if (strongest != null && strongest.isTrigger()) p.close(strongest); } } // Check if we should start a position if (empty(openPositions()) && shouldCalcMoves()) { // Calculate 2 current moves backwards in time var time = currentTime(); currentMoves = map(falseTrue(), isShort -> { new LivePullbackToProfitAnalysis a; a.pullbackLimit(maxPullback); a.isShort(isShort); int idx = actualTicker.indexOfTimestamp(currentTime()); while (idx >= 0 && !a.done()) a.feed(actualTicker.getPricePoint(idx--)); ret a; }); bool shouldShort = false, shouldLong = false; PullbackToProfit openReason = null; for (move : currentMoves) for (ptp : move.ptpList()) if (ptp.cleanness() >= minCleanness && ptp.profit() >= minProfit) { openReason = ptp; if (openReason.isShort) shouldLong = true; else shouldShort = true; } if (shouldShort && shouldLong) print("Conflicting signal (long+short at once)"); else if (shouldShort || shouldLong) { int direction = shouldShort ? -1 : 1; new Position p; p.marginToUse = marginPerPosition; var callbackRate = openReason.pullback*callbackFactor; p.juicer = new CallbackJuicer(callbackRate); p.juicer.juiceable(new ProfitBeforeLeverageJuiceable(p)); openPosition(p, direction, openReason); } } } bool shouldCalcMoves() { /*if (!differentByEpsilonRatio(lastPriceReactedTo, currentPrice, minChangeToReactTo/100)) false; lastPriceReactedTo(currentPrice); true;*/ var time = currentTime(); if (time >= movesCalced+fromSeconds(calcMovesEvery)) { movesCalced = time; true; } false; } L<? extends Position> openPositions() { ret (L) super.openPositions(); } LS status() { ret listCombine( map(currentMoves, move -> "Move: " + move), super.status() ); } }
Began life as a copy of #1036259
download show line numbers debug dex old transpilations
Travelled to 2 computer(s): mqqgnosmbjvj, wnsclhtenguj
No comments. add comment
Snippet ID: | #1036518 |
Snippet name: | CleanMoveStrategy [OK, for one coin at a time] |
Eternal ID of this version: | #1036518/24 |
Text MD5: | 94555821f69917dc9700d40612fc0f9f |
Transpilation MD5: | adc080c1457fd60eee2d546e040f7598 |
Author: | stefan |
Category: | javax / trading |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2023-01-22 17:06:35 |
Source code size: | 3681 bytes / 118 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 180 / 352 |
Version history: | 23 change(s) |
Referenced in: | [show references] |