Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge #15

Merged
merged 28 commits into from
Aug 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0a47199
Updated Path to UIconfig.js file in setup instructions.
ACregan Jul 9, 2018
61a5cf9
Merge pull request #2346 from askmike/develop
askmike Jul 21, 2018
f936339
v0.6.5 (#2428)
askmike Aug 10, 2018
97a9b6d
Disconnect child processes, fix #2457
eusorov Aug 22, 2018
e12eea0
make sure the balance & exposure always gets reset after sync
askmike Aug 22, 2018
47f4a49
bundle current version ws dep, fix #2476
askmike Aug 24, 2018
1f0ee10
init trailing stop
askmike Aug 11, 2018
d238016
add tests for trailing stop
askmike Aug 11, 2018
41107a6
[TEST] also check spy pre trigger
askmike Aug 11, 2018
48a3ab9
[TEST] stop should only trigger once
askmike Aug 11, 2018
90a13a6
[TEST] check whether the trailing stop trails up
askmike Aug 11, 2018
0ba7ba1
init strategy stop API
askmike Aug 11, 2018
11fc34f
init paper trader stop implementation
askmike Aug 11, 2018
8de1c83
[DOCS] add trigger events
askmike Aug 13, 2018
cf495ff
add trigger event subscriptions
askmike Aug 13, 2018
e7da592
implement triggerCreated & triggerAborted in paper trader
askmike Aug 13, 2018
25698c8
implement triggerFired event
askmike Aug 13, 2018
1b8a707
rewire stop prop into trigger & init paper trader glue
askmike Aug 14, 2018
5484ebb
[TEST] price swings around trail
askmike Aug 14, 2018
2e0b4e2
[DOCS] cleanup tmp copy/paste
askmike Aug 14, 2018
a7038a7
mv triggers into gekko broker
askmike Aug 15, 2018
7a26284
[GB] init real trader trigger glue
askmike Aug 15, 2018
a63d927
only create trigger after init trade is completed
askmike Aug 16, 2018
331ceeb
[GB] rewire live trigger to init exec price
askmike Aug 17, 2018
a418c4a
make sure we only move the trail up
askmike Aug 27, 2018
5a798fb
when empty data returns, loader never finishes and never get killed
Aug 23, 2018
f27b3ce
v0.6.6
askmike Aug 27, 2018
95d1873
Merge branch 'stable' into develop
askmike Aug 27, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions core/tools/candleLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const handleCandles = (err, data) => {
util.die('Encountered an error..')
}

if(_.size(data) && _.last(data).start >= toUnix)
if(_.size(data) && _.last(data).start >= toUnix || iterator.from.unix() >= toUnix)
DONE = true;

batcher.write(data);
Expand All @@ -97,4 +97,4 @@ const handleCandles = (err, data) => {

const handleBatchedCandles = candle => {
result.push(candle);
}
}
3 changes: 2 additions & 1 deletion core/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ var util = {
tools: ROOT + 'core/tools/',
workers: ROOT + 'core/workers/',
web: ROOT + 'web/',
config: ROOT + 'config/'
config: ROOT + 'config/',
broker: ROOT + 'exchange/'
}
},
inherit: function(dest, source) {
Expand Down
6 changes: 5 additions & 1 deletion core/workers/loadCandles/child.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ process.send('ready');
process.on('message', (m) => {
if(m.what === 'start')
start(m.config, m.candleSize, m.daterange);
});
});

process.on('disconnect', function() {
process.exit(0);
})
2 changes: 1 addition & 1 deletion core/workers/loadCandles/parent.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ module.exports = (config, callback) => {

// else we are done and have candles!
done(null, m);
child.kill('SIGINT');
this.disconnect();
});

child.on('exit', code => {
Expand Down
51 changes: 48 additions & 3 deletions docs/internals/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Note that all events from Gekko come from a plugin (with the exception of the `c

- [candle](#candle-event): Every time Gekko calculates a new one minute candle from the market.
- [stratWarmupCompleted](#stratWarmupCompleted-event): When the strategy is done warming up.
- [advice](#advice-event): Every time the trading strategy is fed a new candle.
- [advice](#advice-event): Every time the trading strategy has a new trading signal.
- [stratUpdate](#stratUpdate-event): Every time the strategy has processed a new strat candle.
- [stratNotification](#stratNotification-event): Every time the strategy emit new strategy notification.
- [tradeInitiated](#tradeInitiated-event): Every time a trading plugin (either the live trader or the paper trader) is going to start a new trade (buy or sell).
Expand All @@ -25,8 +25,11 @@ trader) has NOT acted on new advice (due to unsufficiant funds or a similar reas
- [portfolioValueChange](#portfolioValueChange-event): Every time value of the portfolio has changed.
- [performanceReport](#performanceReport-event): Every time the profit report was updated.
- [roundtrip](#roundtrip-event): Every time a new roundtrip has been completed.
- [triggerCreated](#triggerCreated-event): Every time a trader has created a new trigger.
- [triggerFired](#triggerFired-event): Every time a created trigger has fired.
- [triggerAborted](#triggerAborted-event): Every time a created trigger has been aborted due to new advice.

Beside those there are also two additional market events that are only emitted when Gekko is running in either realtime or importing mode (NOT during a backtest for performance reasons).
Beside those there are also two additional market events that are only emitted when Gekko is running in realtime mode (NOT during a backtest for performance reasons).

- [marketStart](#marketStart-event): Once, when the market just started.
- [marketUpdate](#marketUpdate-event): Whenever the market has fetched new raw market data.
Expand Down Expand Up @@ -123,7 +126,11 @@ and will start signaling advice.
{
recommendation: [position to take, either long or short],
date: [moment object of this advice],
id: [string identifying this unique trade]
id: [string identifying this unique trade],
trigger: {
type: [type of trigger, currently always "trailingStop"],
// optional parameters per type of trigger
}
}

### tradeInitiated event
Expand Down Expand Up @@ -297,6 +304,44 @@ and will start signaling advice.
profit: -0.2320439659276161,
}

### triggerCreated event

- What: A summary of a created trigger.
- When: After a buy advice that includes a stop.
- Subscribe: You can subscribe to this event by registering the `processTriggerCreated` method.
- Example:
{
id: [string identifying this trigger],
date: Moment<'2017-03-25 19:41:00'>,
type: type: "trailingStop",
properties: {
initialPrice: 100,
trail: 10
}
}

### triggerFired event

- What: A message indicating a created trigger has fired
- When: As soon as the trigger fired
- Subscribe: You can subscribe to this event by registering the `processTriggerFired` method.
- Example:
{
id: [string identifying this trigger],
date: Moment<'2017-03-25 19:41:00'>
}

### triggerAborted event

- What: A message indicating a created trigger has been aborted
- When: After an advice signal indicating a sell
- Subscribe: You can subscribe to this event by registering the `processTriggerAborted` method.
- Example:
{
id: [string identifying this trigger],
date: Moment<'2017-03-25 19:41:00'>
}

### marketStart event

- What: A moment object describing the first date of the market data.
Expand Down
16 changes: 12 additions & 4 deletions docs/strategies/creating_a_strategy.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,21 @@ Most strategies need to warmup before the trading strategy can be started. For e

If you find out in the check function that you want to give new advice to the trader you can use the advice function:

this.advice('short');
// or
this.advice('long');
this.advice({
direction: 'long' // or short
trigger: { // ignored when direction is not "long"
type: 'trailingStop',
trailPercentage: 5
// or:
// trailValue: 100
}
});

The trigger is optional, if the direction is long and the trigger is specified as a trailingStop this will request the trader to create a trail stop trigger.

### candle variable

The following list of candle variables will be available when writing strategies:
The following list of candle variables will be available when writing strategies, they are part of the candle object which is given to your `update` and `check` functions (it's also accessable through `this.candle`).

- candle.close: the closing price of the candle
- candle.high: the highest price of the candle
Expand Down
12 changes: 12 additions & 0 deletions exchange/gekkoBroker.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ const errors = require('./exchangeErrors');
const Portfolio = require('./portfolioManager');
// const Market = require('./market');
const orders = require('./orders');
const Trigger = require('./trigger');
const exchangeUtils = require('./exchangeUtils');
const bindAll = exchangeUtils.bindAll;
const isValidOrder = exchangeUtils.isValidOrder;



class Broker {
constructor(config) {
this.config = config;
Expand Down Expand Up @@ -157,6 +160,15 @@ class Broker {

return order;
}

createTrigger({type, onTrigger, props}) {
return new Trigger({
api: this.api,
type,
onTrigger,
props
});
}
}

module.exports = Broker;
80 changes: 80 additions & 0 deletions exchange/trigger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// wraps around a low level trigger and feeds
// it live market data.

const _ = require('lodash');

const exchangeUtils = require('./exchangeUtils');
const bindAll = exchangeUtils.bindAll;

const triggers = require('./triggers');

// @param api: a gekko broker wrapper instance
// @param type: type of trigger to wrap
// @param props: properties to feed to trigger
class Trigger {
constructor({api, type, props, onTrigger}) {
this.onTrigger = onTrigger;
this.api = api;

this.isLive = true;

// note: we stay on the safe side and trigger
// as soon as the bid goes below trail.
this.tickerProp = 'bid';

if(!_.has(triggers, type)) {
throw new Error('Gekko Broker does not know trigger ' + type);
}

this.CHECK_INTERVAL = this.api.interval * 10;

bindAll(this);
this.trigger = new triggers[type]({
onTrigger: this.propogateTrigger,
...props
})

this.scheduleFetch();
}

scheduleFetch() {
this.timout = setTimeout(this.fetch, this.CHECK_INTERVAL);
}

fetch() {
if(!this.isLive) {
return;
}
this.api.getTicker(this.processTicker)
}

processTicker(err, ticker) {
if(!this.isLive) {
return;
}

if(err) {
return console.log('[GB/trigger] failed to fetch ticker:', err);
}

this.price = ticker[this.tickerProp];

this.trigger.updatePrice(this.price);
this.scheduleFetch();
}

cancel() {
this.isLive = false;
clearTimeout(this.timout);
}

propogateTrigger(payload) {
if(!this.isLive) {
return;
}
this.isLive = false;
this.onTrigger(payload);
}
}

module.exports = Trigger;
3 changes: 3 additions & 0 deletions exchange/triggers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const trailingStop = require('./trailingStop');

module.exports = { trailingStop };
62 changes: 62 additions & 0 deletions exchange/triggers/trailingStop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const EventEmitter = require('events');

// Note: as of now only supports trailing the price going up (after
// a buy), on trigger (when the price moves down) you should sell.


// @param initialPrice: initial price, preferably buy price
// @param trail: fixed offset from the price
// @param onTrigger: fn to call when the stop triggers
class TrailingStop extends EventEmitter {
constructor({trail, initialPrice, onTrigger}) {
super();

this.trail = trail;
this.isLive = true;
this.onTrigger = onTrigger;

this.previousPrice = initialPrice;
this.trailingPoint = initialPrice - this.trail;
}

updatePrice(price) {
if(!this.isLive) {
return;
}

if(price > this.trailingPoint + this.trail) {
this.trailingPoint = price - this.trail;
}

this.previousPrice = price;

if(price <= this.trailingPoint) {
this.trigger();
}
}

updateTrail(trail) {
if(!this.isLive) {
return;
}

this.trail = trail;
this.trailingPoint = this.previousPrice - this.trail;
// recheck whether moving the trail triggered.
this.updatePrice(this.previousPrice);
}

trigger() {
if(!this.isLive) {
return;
}

this.isLive = false;
if(this.onTrigger) {
this.onTrigger(this.previousPrice);
}
this.emit('trigger', this.previousPrice);
}
}

module.exports = TrailingStop;
1 change: 1 addition & 0 deletions exchange/wrappers/binance.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ Trader.prototype.isValidPrice = function(price) {
}

Trader.prototype.isValidLot = function(price, amount) {
console.log('isValidLot', this.market.minimalOrder.order, amount * price >= this.market.minimalOrder.order)
return amount * price >= this.market.minimalOrder.order;
}

Expand Down
22 changes: 15 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading