Warning: session_start(): open(/var/lib/php/sessions/sess_8suu8ph0g2nkvhkklgo1ufkj31, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
concept Chaser extends G22TradingStrategy {
// Juicer parameters
settable double maxLoss = 0.6;
settable double pullback = 0.4;
// internal
// trigger = 0 to 1
record noeq CloseSignal(S reason, double trigger) {}
persistable record Juicer(double maxLoss, double pullback) {
L closeSignals(Position p) {
new L signals;
// How close are we to the max closing time?
if (maxClosingTime() < infinity())
signals.add(new CloseSignal("Age", transformToZeroToOne(time, p.openingTime(), maxClosingTime())));
// How close are we to our loss limit?
if (p.profit < 0)
signals.add(new CloseSignal("Loss", doubleRatio(-p.profit, maxLoss));
else
// How close are we to the pullback limit?
signals.add(new CloseSignal("Profit", transformToZeroToOne(p.profit,
p.crest, p.crest-pullback));
ret signals;
}
}
persistable class Position extends G22TradingStrategy.Position {
settable Juicer juicer;
L closeSignals() {
ret juicer == null ?: juicer.closeSignals(this);
}
// >= 1 to close
// otherwise keep open
double closeSignal() {
CloseSignal strongestSignal = closeSignalWithDescription();
ret strongestSignal == null ? 0 : strongestSignal.trigger;
}
CloseSignal closeSignalWithDescription() {
ret highestBy(closeSignals(), signal -> signal.trigger);
}
}
Position openPosition(int direction) {
if (nempty(openPositions())) {
log("Not opening a second position");
null;
}
new Position p;
p.juicer(new Juicer(maxLoss, pullback));
ret openPosition(p, direction);
}
void start {
if (started()) fail("Already started");
if (currentPrice() == 0)
ret with primed(true);
// Save starting price, create price cells & digitizer
startingPrice = currentPrice();
var priceCells = makePriceCells(startingPrice);
digitizer = new PriceDigitizer2(priceCells);
digitizer.verbose(verbose);
log("Starting CHASER at " + startingPrice + " +/- " + cellSize);
}
void price(double price) {
if (currentPrice == price) ret;
currentPrice = price;
if (!started()) {
if (primed) {
primed(false);
start();
}
ret;
}
digitizer.digitize(price);
direction = sign(digitizedPrice()-lastDigitizedPrice());
nextStep();
if (started())
step();
print(this);
}
swappable void step {
// Find positions to close
L toClose = new L;
/*for (p : p.juicer.closeReasons(p)) {
cast p to Position;
p.closeReason("WIN");
log("Closing winner position at " + currentPrice + " (" + p1 + " -> " + p2 + "): " + p);
toClose.add(p);
}*/
double p1 = lastDigitizedPrice();
double p2 = digitizedPrice();
direction = sign(p2-p1);
if (direction == 0) ret;
closePositions(toClose);
// TODO: open new position
afterStep();
}
S baseToString() {
ret colonCombine(
_conceptID() == 0 ? "" : "Strategy " + _conceptID(),
"Chaser");
}
// Chaser.toString
toString { ret baseToString(); }
Position openShort() { ret openPosition(-1); }
Position openLong() { ret openPosition(1); }
}