first commit

This commit is contained in:
Francois Klieber committed 2021-06-06 20:25:14 +02:00
commit aa7869eb33
386 files changed
+69375

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
# Gekko's architecture
![Gekko architecture](https://wizb.it/gekko/static/architecture.jpg)
Every Gekko instance has two core components:
- A market
- A GekkoStream
Communication between those two components is handled by Node.JS' [Stream API](https://nodejs.org/api/stream.html). The Market implements a Readable Stream interface while the GekkoStream implements a Writeable Stream interface.
## A Market
All markets in Gekko eventually output `candle` data. Where these candles come from and how old they are does not matter to the GekkoStream they get piped into. On default Gekko looks for markets in the [`core/markets/` directory](https://github.com/askmike/gekko/tree/stable/core/markets). The top orange block in the picture is a BudFox market (the default semi-realtime market that gets live data from exchanges).
Example Markets that come included with Gekko are:
- **BudFox** (a realtime market): this market stays on indefinitely and outputs candles from the live markets in semi-realtime (cryptocurrency exchanges run 24/7).
- **backtest**: this market reads candles from a database and outputs them as fast as the GekkoStream is able to consume them (the GekkoStream will run TA strategies over these candles).
- **importer**: the importer market will fetch historical data from an exchange and pass on (to the GekkoStream who inserts them in a database).
## A GekkoStream
A GekkoStream is nothing more than a collection of [plugins](../commandline/plugins.md). Plugins are simple modules that can subscribe to events, and do something based on event data. The most basic event every GekkoStream has is the "candle" event, this event comes from the market.
However **plugins are allowed to broadcast their own events, which other plugins can subscribe to**. An example of this is the `tradingAdvisor` plugin. This plugin will implement a [strategy](../strategies/introduction.md) that will be fed candle data. As soon as the strategy suggests to take a certain position in the market ("I detect an uptrend, I advice to go **long**") it will broadcast an `advice` event. The `paperTrader` is a plugin that simulates trading using these advices, the `trader` is a plugin that creates real market orders based on these advices. You can decide to only turn the `paperTrader` on or to turn the `trader` on (you now have a live trading bot).
When you run a backtest using Gekko the following things happen:
- Gekko configures a `backtest` market.
- Gekko loads all configured plugins that are supported in the `backtest` mode* into a GekkoStream.
- Gekko pipes the market into the GekkoStream and voila!
\*Gekko refuses to load plugins that are unsupported in specific modes. During backtests you **never** want to enable the real trader to enter market orders. Because if you would the advice would be based on specific moments in the backtest, not on the current state of the market.
## Plugins & Adapters
Those two core components describe the majority of Gekko's flow. A lot "core functionality" like saving candles to disk are simply plugins that push all candles to a database.
## Separated architecture
The modular nature of Gekko makes it very dynamic and allows for rapidly creating new plugins. However there is an ugly side to this story:
The `tradingAdvisor` runs TA strategies against a market. The problem however is that most TA indicators need some history before they can give accurate results. If you want to use an EMA (exponential moving average), you need some history to base the initial average on. But because the tradingAdvisor doesn't know what market data is going to be made available later by the market, it needs to do some fetching itself and compare that to locally available market data (stored in the local database) to see if it can stitch the two sources.
+41
View File
@@ -0,0 +1,41 @@
# BudFox
**Similar to the [movie Wallstreet](https://en.wikipedia.org/wiki/Wall_Street_(1987_film)), Gekko delegates the dirty work of getting fresh data to Bud Fox. Bud Fox delivers the data to Gekko who uses this data to make investment decisions.**
Whenever Gekko works with realtime market data, it spawns a BudFox to fetch and transform the data for every market (exchange + asset + pair, for example: `bitstamp USD/BTC`). Bud Fox will keep on fetching data from the market in semi-realtime, turn historical trades into minutely candles (and make sure every minute of data has a candle).
BudFox exposes a stream of `candles` which are fed to Gekko.
## Advanced Usage
BudFox is a small part of Gekko's core that aggregates realtime market data from any supported exchange into a readable stream of candles. Example usage:
var config = {
exchange: 'Bitstamp',
currency: 'USD',
asset: 'BTC'
}
new BudFox(config)
.start()
// convert JS objects to JSON string
.pipe(new require('stringify-stream')())
// output to standard out
.pipe(process.stdout);
Outputs:
{"start":"2015-02-02T23:08:00.000Z","open":238.21,"high":239.35,"low":238.21,"close":238.66,"vwp":8743.778447997309,"volume":203.6969347,"trades":56}
{"start":"2015-02-02T23:09:00.000Z","open":239.03,"high":240,"low":238.21,"close":239.19,"vwp":8725.27119145289,"volume":323.66383462999994,"trades":72}
{"start":"2015-02-02T23:10:00.000Z","open":239.19,"high":239.8,"low":234.68,"close":235,"vwp":6664.509955946812,"volume":114.67727173,"trades":48}
{"start":"2015-02-02T23:11:00.000Z","open":237.77,"high":238.51,"low":235,"close":238.1,"vwp":3158.835462414369,"volume":41.47081054999999,"trades":28}
{"start":"2015-02-02T23:12:00.000Z","open":237,"high":238,"low":236.78,"close":237.9,"vwp":1634.5173557116634,"volume":70.58755061,"trades":22}
{"start":"2015-02-02T23:13:00.000Z","open":237.95,"high":238.49,"low":237.95,"close":238.49,"vwp":604.219141331534,"volume":12.196531389999999,"trades":7}
{"start":"2015-02-02T23:14:00.000Z","open":238.51,"high":241,"low":237.89,"close":241,"vwp":7610.305142999085,"volume":579.5321983399998,"trades":67}
{"start":"2015-02-02T23:15:00.000Z","open":238.12,"high":239.76,"low":238.12,"close":239.1,"vwp":1828.5872875471068,"volume":31.16232463,"trades":17}
{"start":"2015-02-02T23:16:00.000Z","open":239.1,"high":239.76,"low":239.1,"close":239.67,"vwp":1339.3753800771717,"volume":5.56431998,"trades":12}
{"start":"2015-02-02T23:17:00.000Z","open":239.27,"high":239.99,"low":239.25,"close":239.92,"vwp":1519.3392752690336,"volume":6.984999999999999,"trades":14}
{"start":"2015-02-02T23:18:00.000Z","open":239.92,"high":239.98,"low":238.98,"close":238.98,"vwp":4162.807256131301,"volume":21.17212333,"trades":29}
{"start":"2015-02-02T23:19:00.000Z","open":239,"high":239,"low":238.15,"close":238.33,"vwp":1627.2581467076204,"volume":31.682705360000003,"trades":15}
{"start":"2015-02-02T23:20:00.000Z","open":238.33,"high":239.95,"low":238.33,"close":239,"vwp":3648.661808492067,"volume":128.35564560999998,"trades":23}
// etc..
+359
View File
@@ -0,0 +1,359 @@
# Events
As described in the [architecture](./architecture.md) events play a key role in the complete system: they relay all information between separate components (like [plugins](./plugins.md)). This makes the codebase scalable, testable and it separates concerns.
if you run the Gekko UI events are relayed between core components as well as broadcasted (via the UI server) to the web UI. This means that all events broadcasted by any plugin automatically end up in the web UI.
Note that all events from Gekko come from a plugin (with the exception of the `candle` event, which comes from the market), and no plugin is required for Gekko to run, this means it might be possible that some events are never broadcasted since their originating plugin is not active. If a plugin wants to listen to an event that will never be broadcasted (because of a lack of another plugin) this will be warned in the console like so:
(WARN): Paper Trader wanted to listen to the tradingAdvisor, however the tradingAdvisor is disabled.
## List of events emitted by standard plugins
- [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 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).
- [tradeCompleted](#tradeCompleted-event): Every time a trading plugin (either the live trader or the paper trader) has completed a trade.
- [tradeAborted](#tradeAborted-event): Every time a trading plugin (either the live trader or the paper trader) has NOT acted on new advice (due to insufficient funds or a similar reason).
trader) has NOT acted on new advice (due to unsufficiant funds or a similar reason).
- [tradeErrored](#tradeErrored-event): Every time the live trader was unable to execute an initialized.
- [tradeCancelled](#tradeCancelled-event): Every time the live trader cancelled a not yet executed trade.
- [portfolioChange](#portfolioChange-event): Every time the content of the portfolio has changed.
- [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 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.
### candle event
- What: An object containing a one minute candle from the market.
- When: In liquid markets roughly every minute.
- Subscribe: Your plugin can subscribe to this event by registering the `processCandle` method.
- Async: When subscribing to this event the second argument will be a callback which you are expected to call when done handling this event.
- Notes:
- Depending on the gekko configuration these candles might be historical on startup. If this is a concern for consumers, make sure to deal with this properly.
- In illiquid markets (of less than a trade per minute) Gekko will calculate these candles in batches and a few might come at the same time.
- These are always one minute candles, this is the lowest level of market data flowing through a gekko stream.
- Example:
{
start: [moment object of the start time of the candle],
open: [number, open of candle],
high: [number, high of candle],
low: [number, low of candle],
close: [number, close of candle],
vwp: [number, average weighted price of candle],
volume: [number, total volume volume],
trades: [number, amount of trades]
}
### stratWarmupCompleted event
- What: An object signaling that the strategy is now completely warmed up
and will start signaling advice.
- When: Once the strategy consumed more market data than defined by the required history.
- Subscribe: You can subscribe to this event by registering the `processWarmupCompleted` method.
- Notes:
- This event is triggered on init when the strategy does not require any history (and thus no warmup time).
- Example:
{
start: [moment object of the start time of the first candle after the warmup],
}
### stratCandle event
- What: An object describing an updated strat candle the strat has processed.
- When: when the strategy is initialized is started.
- Subscribe: You can subscribe to this event by registering the `processStratCandle` method.
- Notes:
- This is the candle that the strategy sees: if you configured the candleSize to 60 (minutes) this event will contain a 60 minute candle.
- Strat Candles are emitted while the strategy is still warming up (before the `stratWarmupCompleted` event).
- Example:
{
start: [moment object of the start time of the candle],
open: [number, open of candle],
high: [number, high of candle],
low: [number, low of candle],
close: [number, close of candle],
vwp: [number, average weighted price of candle],
volume: [number, total volume volume],
trades: [number, amount of trades]
}
### stratUpdate event
- What: An object describing updated state of the strategy based on a new strat candle.
- When: when the strategy has
- Subscribe: You can subscribe to this event by registering the `processStratUpdate` method.
- Notes:
- Strat updates are emitted while the strategy is still warming up (before the `stratWarmupCompleted` event).
- Example:
{
date: [moment object of the start time of the candle],
indicators: {
mymacd: [number, result of running this indicator over current candle]
}
}
### stratNotification event
- What: An object describing new notification from your strategy
- When: when the strategy emit using `this.notify()` function
- Subscribe: You can subscribe to this event by registering the `processStratNotification` method.
- Example:
{
date: [moment object of the start time of the candle],
content: [String content notification in strategy]
}
### advice event
- What: An advice from the strategy, the advice will either be LONG or SHORT.
- When: This depends on the strategy and the candleSize.
- Subscribe: You can subscribe to this event by registering the `processAdvice` method.
- Example:
{
recommendation: [position to take, either long or short],
date: [moment object of this advice],
id: [string identifying this unique trade],
trigger: {
type: [type of trigger, currently always "trailingStop"],
// optional parameters per type of trigger
}
}
### tradeInitiated event
- What: An object signaling that a new trade will be executed.
- When: At the same time as the advice event if the trader will try to trade.
- Subscribe: You can subscribe to this event by registering the `processTradeInitiated` method.
- Example:
{
id: [string identifying this unique trade],
adviceId: [number specifying the advice id this trade is based on],
action: [either "buy" or "sell"],
date: [moment object, exchange time trade completed at],
portfolio: [object containing amount in currency, asset and total balance],
balance: [number, total worth of portfolio]
}
### tradeAborted event
- What: An object signaling the fact that the trader will ignore the advice.
- When: At the same time as the advice event if the trader will NOT try to trade.
- Subscribe: You can subscribe to this event by registering the `processTradeAborted` method.
- Example:
{
id: [string identifying this unique trade],
adviceId: [number specifying the advice id this trade is based on],
action: [either "buy" or "sell"],
date: [moment object, exchange time trade completed at],
reason: [string explaining why the trade was aborted]
}
### tradeCancelled event
- What: An object signaling the fact that the a trade originally initiated was now cancelled.
- When: After a receiving a tradeInitiated event and than a advice event (without a tradeCompleted event between them).
- Subscribe: You can subscribe to this event by registering the `processTradeCanceled` method.
- Example:
{
id: [string identifying this unique trade],
adviceId: [number specifying the advice id this trade is based on],
date: [moment object, exchange time trade completed at]
}
### tradeErrored event
- What: An object singaling the fact that the a trade orginially initiated was now cancelled
- When: After a tradeInitiated event
- Subscribe: You can subscribe to this event by registering the `processTradeErrored` method.
- Example:
{
id: [string identifying this unique trade],
adviceId: [number specifying the advice id this trade is based on],
date: [moment object, exchange time trade completed at],
reason: [string explaining why the trade was aborted]
}
### tradeCompleted event
- What: Details of a completed trade.
- When: Some point in time after the tradeInitiated event.
- Subscribe: You can subscribe to this event by registering the `processTradeCompleted` method.
- Example:
{
id: [string identifying this unique trade],
adviceId: [number specifying the advice id this trade is based on],
action: [either "buy" or "sell"],
price: [number, average price that was sold at],
amount: [number, how much asset was trades (excluding "cost")],
cost: [number the amount in currency representing fee, slippage and other execution costs],
date: [moment object, exchange time trade completed at],
portfolio: [object containing amount in currency and asset],
balance: [number, total worth of portfolio],
feePercent: [the cost in fees],
effectivePrice: [executed price - fee percent, if effective price of buy is below that of sell you are ALWAYS in profit.]
}
### portfolioChange event
- What: An object containing new portfolio contents (amount of asset & currency).
- When: Some point in time after the advice event, at the same time as the tradeCompleted event.
- Subscribe: You can subscribe to this event by registering the `processPortfolioChange` method.
- Example:
{
currency: [number, portfolio amount of currency],
asset: [number, portfolio amount of asset],
}
### portfolioValueChange event
- What: An object containing the total portfolio worth (amount of asset & currency calculated in currency).
- When: Every time the value of the portfolio has changed, if the strategy is in a LONG position this will be every minute.
- Subscribe: You can subscribe to this event by registering the `processPortfolioValueChange` method.
- Example:
{
value: [number, portfolio amount of currency]
}
### performanceReport event
- What: An object containing a summary of the performance of the "tradebot" (advice signals + execution).
- When: Once every new candle.
- Subscribe: You can subscribe to this event by registering the `processPerformanceReport` method.
- Example:
{
startTime: Moment<'2017-03-25 19:41:00'>,
endTime: Moment<'2017-03-25 20:01:00'>,
timespan: 36000000,
market: -0.316304880517734,
balance: 1016.7200029226638,
profit: -26.789997197336106,
relativeProfit: -2.5672966425099304,
yearlyProfit: '-704041.12634599',
relativeYearlyProfit: '-67468.55576516',
startPrice: 945.80000002,
endPrice: 942.80838846,
trades: 10,
roundtrips: 5,
startBalance: 1043.5100001199999,
sharpe: -2.676305165560598
}
### roundtripInitiated event
- What: A summary of a started roundtrip.
- When: After every tradeCompleted with action `buy`.
- Subscribe: You can subscribe to this event by registering the `processRoundtripInitiated` method.
- Example:
{
id: [string identifying this roundtrip],
entryAt: Moment<'2017-03-25 19:41:00'>,
entryPrice: 10.21315498,
entryBalance: 98.19707799420277,
exitAt: Moment<'2017-03-25 19:41:00'>,
exitPrice: 10.22011632,
exitBalance: 97.9692176,
duration: 3600000,
pnl: -0.2278603942027786,
profit: -0.2320439659276161,
}
### roundtripUpdate event
- What: An updated summary of a currently open roundtrip.
- When: On every candle for as long as the bot is in a long position.
- Subscribe: You can subscribe to this event by registering the `processRoundtripUpdate` method.
- Example:
{
id: [string identifying this roundtrip],
at: Moment<'2017-03-25 19:41:00'>,
duration: 3600000,
uPnl: -0.2278603942027786,
uProfit: -0.2320439659276161,
}
### roundtrip event
- What: A summary of a completed roundtrip (buy + sell signal).
- When: After every roundtrip: a completed sell trade event that superceded a buy sell trade event.
- Subscribe: You can subscribe to this event by registering the `processRoundtrip` method.
- Example:
{
id: [string identifying this roundtrip],
entryAt: Moment<'2017-03-25 19:41:00'>,
entryPrice: 10.21315498,
entryBalance: 98.19707799420277,
exitAt: Moment<'2017-03-25 19:41:00'>,
exitPrice: 10.22011632,
exitBalance: 97.9692176,
duration: 3600000,
pnl: -0.2278603942027786,
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.
- When: When the market is started.
- Subscribe: Your plugin can subscribe to this event by registering the `processMarketStart` method.
- Example:
[moment object describing the date of the first market data]
### marketUpdate event
- What: A moment object describing the point in time for up to which the market has market data.
- When: Every few seconds.
- Subscribe: Your plugin can subscribe to this event by registering the `processMarketUpdate` method.
- Example:
[moment object describing the date of the latest market data]
+57
View File
@@ -0,0 +1,57 @@
# Gekko UI
When you launch Gekko UI, you start a basic nodejs webserver with 3 components:
- It will serve frontend (HTML/CSS/JS) files for frontend written as a [vuejs app](https://vuejs.org/) (v2.5.16).
- It will will handle API requests as [koa](http://koajs.com/) (v1) routes, it will also start a websocket server used to broadcast messages in realtime (used for long lived processes Importing and Live Gekkos for example). The server API documentation can be found [here](./server_api.md).
## Gekko UI Frontend
The frontend is setup as a very basic vue app. Additionally the following libraries are used:
- [Reconnecting websocket](https://github.com/joewalnes/reconnecting-websocket)
- [Moment](http://momentjs.com/)
- [d3.js](https://d3js.org/)
- [toml](https://github.com/BinaryMuse/toml-node)
- [humanizeDuration](https://github.com/EvanHahn/HumanizeDuration.js)
The vue app itself uses the following libraries:
- [marked](https://github.com/chjj/marked)
- [pug](https://github.com/pugjs) (all html is either written in pug of markdown)
- [vue-router](https://github.com/vuejs/vue-router)
- [vuex](https://github.com/vuejs/vuex)
- [superagent](https://github.com/visionmedia/superagent) (cross browser ajax)
### Developing for the Gekko UI frontend
You first need to install all developer dependencies so the frontend app can be recompiled on your machine.
cd gekko/web/vue
npm install
After this you can launch a hot reload version of the app which will automatically recompile the frontend and reload your browser:
# path to webserver
cd gekko/web
# launch the server - we use this API
node server
# path to vue app
cd vue
npm run serve
Gekko UI is now served from port 8080, the webpack dev server will compile the vue app (in memory) and intercept all calls to the app itself (`/dist/js/app.xxx.js`) and serve the in memory app. It is important to note that this UI still talks to the API served from the `node server` command (on default http://localhost:3000/api).
If you have configured Gekko to run on non standards ports (using the UIconfig), you can have your config applied to the development environment by copying `gekko/web/vue/dist/UIconfig.js` to `gekko/web/vue/public/UIconfig.js`.
### Compiling the Gekko UI frontend
*Note: as part of the compilation process Gekko will reset the UIconfig in both `gekko/web/vue/dist/UIconfig.js` and `gekko/web/vue/public/UIconfig.js`. Only compile if you are ready to lose your personal changes.*
When you are done developing you can compile the app using these instructions:
# path to vue app
cd gekko/web/vue
npm run build
+37
View File
@@ -0,0 +1,37 @@
# Plugins
*This is a technical document explaining the role of Plugins in the Gekko codebase. For a non technical document about available plugins, see [here](../commandline/plugins.md).*
Within Gekko most functionality is encapsulated into "plugins". These are simple modules that process some data (from [Gekko events](./events.md)) and do something with it. For example emitting a new event or sending a message out to some external service like telegram, or doing a live trade at an exchange.
Whenever you run a Gekko (live trader, paper trader, backtester or importer) you are simply running a number of plugins and feeding them with market data. For a more detailed explanation, see the [architecture doc](./architecture.md).
For example, there is a plugin called the paperTrader which is responsible for simulating trades (used in [backtests](../features/backtesting.md) and [paper trading](../features/paper_trading.md)). It does this by listening to advice events coming from a strategy, and simulating trades whenever they fire (and firing trade events). Find a longer list of plugins that come with Gekko [here](../commandline/plugins.md).
- All plugins are javascript files that expose a constructor function (or ES6 class).
- All plugins are stored in `gekko/plugins`.
- All plugins are described in the file [`gekko/plugins.js`](https://github.com/askmike/gekko/blob/develop/plugins.js), this way Gekko knows how/when the plugin can be used (for example it does not make sense to run a telegram bot that will emit all trades in a backtest).
## Structure of a plugin
A plugin can be a very simple module that simply listens to some event:
// A plugin that will buy Champagne when we MOON
// example: doesn't actually work..
const alexa = require('alexa');
const MOON = 1000000;
const Plugin = function() {}
Plugin.prototype.processPortfolioValueChange = function(event) {
if(event.value > MOON) {
alexa.say('Alexa, buy the best Champagne!');
}
};
module.exports = Plugin;
Have a look at the [events doc](./events.md) for all events your plugin can subscribe to. For technical inspiration it's easiest to look at the code of Gekko's plugins (here [`gekko/plugins.js`](https://github.com/askmike/gekko/blob/develop/plugins.js)).
+795
View File
@@ -0,0 +1,795 @@
# Server API
The Gekko project has three major components:
- [Actual Gekko instance](./architecture.md)
- A nodejs server that:
- starts and manages gekkos
- broadcasts all updates from all gekkos and tracks their overall state
- has API calls to query and manage historical data (by importing more for example)
- [A web UI (vue frontend project)](./gekko_ui.md)
The nodejs server can also be used standalone as a webserver in combination with your own software (such as a new UI, a mobile app or a higher level backtester), see [other software](../extending/other_software.md) for examples).
The server exposes two different APIs: A websocket API to push gekko updates and a REST API for everything else.
When you run `node gekko --ui` it will automatically start a server. You can also do this manually by running:
cd gekko/web
node server
The server will now run on the host/port configured in `gekko/web/vue/public/UIConfig.js` (under api.host).
## REST API
### GET /api/info
Get version information of current running Gekko Server.
NOTE: The API does not have dedicated versioning, instead it uses the version of the complete Gekko project.
**response**
```
{ "version": "0.6.0" }
```
### GET /api/strategies
Get all strategies known to this Gekko. The value of the `params` key is a TOML string.
**response**
```
[
{
"name": "DEBUG_single-advice",
"params": ""
},
{
"name": "DEBUG_toggle-advice",
"params": ""
},
{
"name": "DEMA",
"params": "weight = 21\n\n[thresholds]\ndown = -0.025\nup = 0.025\n"
},
{
"name": "MACD",
"params": "short = 10\nlong = 21\nsignal = 9\n\n[thresholds]\ndown = -0.025\nup = 0.025\npersistence = 1"
},
// etc.
]
```
### GET /api/apiKeys
Returns a list of exchanges that this Gekko has API keys stored for.
NOTE: for security reasons the Gekko never exposes the API keys themselves.
**response**
```
["bitstamp","bitfinex"]
```
### GET /api/imports
Returns a list of currently running data imports.
**response**
```
[
{
"watch": {
"exchange": "poloniex",
"currency": "USDT",
"asset": "BTC"
},
"id": "765606096903592",
"latest": "2018-04-03T07:13:00Z",
"from": "2018-04-03 05:13",
"to": "2018-07-03 05:13",
"done": false
}
]
```
### GET /api/gekkos
Returns a list of currently running and archived Gekkos.
**response**
```
{
"live": {
"2018-07-03-13-14-papertrader-384222057313623": {
"mode": "realtime",
"config": {
// complete config that was passed when creating
},
"id": "2018-07-03-13-14-papertrader-384222057313623",
"type": "leech",
"logType": "papertrader",
"active": true,
"stopped": false,
"errored": false,
"errorMessage": false,
"events": {
"initial": {
"candle": {
"id": 419824,
"start": "2018-07-03T04:47:00.000Z",
"open": 6664.79999887,
"high": 6664.79999887,
"low": 6659.99999989,
"close": 6659.99999989,
"vwp": 6662.402395386147,
"volume": 0.001202,
"trades": 3
},
"portfolioChange": {
"asset": 1,
"currency": 100
},
"portfolioValueChange": {
"balance": 6759.99999989
}
},
"latest": {
"candle": {
"id": 419849,
"start": "2018-07-03T05:12:00.000Z",
"open": 6643.21466865,
"high": 6656.58532982,
"low": 6643.01,
"close": 6656,
"vwp": 6643.884436854498,
"volume": 1.9966113400000003,
"trades": 15
},
"portfolioChange": {
"asset": 1,
"currency": 100
},
"portfolioValueChange": {
"balance": 6756
}
}
},
"start": "2018-07-03T05:14:23.582Z",
"latestUpdate": "2018-07-03T05:14:24.090Z"
}
},
"archive": {}
}
```
### GET /api/exchanges
Returns a list of supported exchanges with meta information (such as supported features and tradable markets).
**response**
```
{
"name": "Bitstamp",
"slug": "bitstamp",
"currencies": [
"USD",
// and more
],
"assets": [
"BTC",
// and more
],
"maxTradesAge": 60,
"maxHistoryFetch": null,
"markets": [
{
"pair": [
"USD",
"EUR"
],
"minimalOrder": {
"amount": 5,
"unit": "currency"
},
"precision": 2
},
// and more
],
"requires": [
"key",
"secret",
"username"
],
"fetchTimespan": 60,
"tid": "tid",
"tradable": true
}
```
### POST /api/addApiKey
Adds an API key for an exchange account to Gekko. As of now only 1 API keypair can be added per exchange.
**request**
```
{
"exchange": "bitstamp",
"values": {
"key": "x",
"secret": "y"
}
}
```
**response**
```
{
"status": "ok"
}
```
### POST /api/removeApiKey
Removes an API key from Gekko.
**request**
```
{
"exchange": "bitstamp"
}
```
**response**
```
{
"status": "ok"
}
```
### POST /api/scan
Scans a daterange to find all datasets for a specific market.
**request**
```
{
"watch": {
exchange: "bitstamp",
"currency": "USD",
"asset": "BTC"
}
}
```
**response**
```
[
{
"to": 1464787560,
"from": 1464783960
},
{
"to": 1479115560,
"from": 1471112760
}
]
```
### POST /api/scansets
Scans the database for all datasets for all markets.
**request**
```
{}
```
**response**
```
{
"datasets": [
{
"exchange": "bitfinex",
"currency": "USD",
"asset": "BTC",
"ranges": [
{
"to": 1508551500,
"from": 1508493900
}
]
},
{
"exchange": "binance",
"currency": "USDT",
"asset": "BTC",
"ranges": [
{
"to": 1514351280,
"from": 1510632480
},
{
"to": 1522915680,
"from": 1522678080
}
]
},
],
"errors": [
{
"exchange": "poloniex",
"currency": "BTC",
"asset": "BTC"
}
]
}
```
### POST /api/backtest
Perform a backtest.
**request**
*(a valid gekko config object)*
Tweak the `config.backtestResultExporter.data` object to control what is included in the output. For example skip `stratCandles` if you only care about the final profit report. This way the server won't include megabytes of candle data in the output.
```
{
"watch": {
"exchange": "poloniex",
"currency": "USDT",
"asset": "ETH"
},
"paperTrader": {
"feeMaker": 0.25,
"feeTaker": 0.25,
"feeUsing": "maker",
"slippage": 0.05,
"simulationBalance": {
"asset": 1,
"currency": 100
},
"reportRoundtrips": true,
"enabled": true
},
"tradingAdvisor": {
"enabled": true,
"method": "MACD",
"candleSize": 60,
"historySize": 10
},
"MACD": {
"short": 10,
"long": 21,
"signal": 9,
"thresholds": {
"down": -0.025,
"up": 0.025,
"persistence": 1
}
},
"backtest": {
"daterange": {
"from": "2016-06-01T11:57:00Z",
"to": "2016-11-13T14:57:00Z"
}
},
"backtestResultExporter": {
"enabled": true,
"writeToDisk": false,
"data": {
"stratUpdates": false,
"roundtrips": true,
"stratCandles": true,
"stratCandleProps": [
"open"
],
"trades": true
}
},
"performanceAnalyzer": {
"riskFreeReturn": 2,
"enabled": true
}
}
```
**response**
```
{
"performanceReport": {
"startTime": "2018-04-02 14:08:00",
"endTime": "2018-04-05 04:08:00",
"timespan": "3 days",
"market": -2.159980297428632,
"startBalance": 7083.86,
"balance": 7424.849452897501,
"profit": 340.989452897501,
"relativeProfit": 4.813610840664566,
"yearlyProfit": 48210.518806418906,
"relativeYearlyProfit": 680.5684867631334,
"startPrice": 6983.86,
"endPrice": 6833.01,
"trades": 3,
"exposure": 0.3709677419354839,
"sharpe": null,
"downside": null,
"alpha": 343.14943319492966
},
"roundtrips": [
{
"id": 0,
"entryAt": 1522685280,
"entryPrice": 7019.99,
"entryBalance": 7119.6899337771,
"exitAt": 1522768080,
"exitPrice": 7365,
"exitBalance": 7447.19106625,
"duration": 82800000,
"pnl": 327.5011324729003,
"profit": 4.599935327508788
},
// and more
],
"stratCandles": [
{
"open": 6990.06,
"start": 1522678080
},
// and more
],
"trades": [
{
"id": "trade-1",
"adviceId": "advice-1",
"action": "buy",
"cost": 0.30000000000000027,
"amount": 1.01420229,
"price": 7019.99,
"portfolio": {
"asset": 1.08661475,
"currency": 0
},
"balance": 7119.6899337771,
"date": 1522685280
},
// and more
]
}
```
### POST /api/import
Start a data import.
**request**
*(a valid gekko config object)*
```
{
"watch": {
"exchange": "poloniex",
"currency": "USDT",
"asset": "BTC"
},
"importer": {
"daterange": {
"from": "2018-04-03 05:46",
"to": "2018-07-03 05:46"
}
},
"candleWriter": {
"enabled": true
}
}
```
**response**
NOTE: this only contains information regarding the started import, updates are pushed through the websocket.
```
{
"watch": {
"exchange": "poloniex",
"currency": "USDT",
"asset": "BTC"
},
"id": "7324830525419355",
"latest": "",
"from": "2018-04-03 05:46",
"to": "2018-07-03 05:46"
}
```
### POST /api/startGekko
Start a gekko instance
**request**
*(a valid gekko config object)*
In order to start a stratRunner, pass a config object that includes plugins required for a stratrunner (such as paperTrader, tradingAdvisor and performanceAnalyzer).
```
{
"watch": {
"exchange": "poloniex",
"currency": "USDT",
"asset": "BTC"
},
"candleWriter": {
"enabled": true,
},
"type": "market watcher",
"mode": "realtime"
}
```
**response**
NOTE: this only contains information regarding the started gekko, updates from are pushed through the websocket.
```
{
"mode": "realtime",
"config": {
// config that was passed in the request
},
"id": "2018-07-03-13-49-watcher-404457189518044",
"type": "watcher",
"logType": "watcher",
"active": true,
"stopped": false,
"errored": false,
"errorMessage": false,
"events": {
"initial": {},
"latest": {}
},
"start": "2018-07-03T05:49:06.685Z"
}
```
### POST /api/stopGekko
Stop a gekko instance
**request**
```
{
"id": "2018-07-03-13-49-watcher-404457189518044"
}
```
**response**
```
{
"status": "ok"
}
```
### POST /api/deleteGekko
Delete a stopped gekko instance from the archive.
**request**
```
{
"id": "2018-07-03-13-49-watcher-404457189518044"
}
```
**response**
```
{
"status": "ok"
}
```
### POST /api/getCandles
Load candles directly from the database.
**request**
```
{
"watch": {
"exchange": "poloniex",
"currency": "USDT",
"asset": "BTC"
},
"daterange": {
"to": "2018-07-03T05:53:00.000Z",
"from": "2018-07-03T05:40:00.000Z"
},
"candleSize": 1
}
```
**response**
```
[
{
"start": 1530596400,
"open": 6645.49999958,
"high": 6649.83970225,
"low": 6642,
"close": 6642,
"vwp": 6644.840723040122,
"volume": 0.007383000000000001,
"trades": 23
},
{
"start": 1530596460,
"open": 6649.69979936,
"high": 6649.69979936,
"low": 6642,
"close": 6648.89999912,
"vwp": 6645.926390922748,
"volume": 0.007383450000000001,
"trades": 21
},
// etc.
]
```
## Websocket API
A websocket server is started at the basepath of the API. Connecting to it means you'll receive update messages. Messages you send to the server via the websocket connection are completely ignored, to control the server use the REST API instead.
The possible messages are:
### import_update
Whenever there is an update regarding a running import.
```
{
type: 'import_update',
import_id: '7324830525419355',
updates: {
latest: '2018-07-03T05:49:06.685Z',
done: false
}
}
```
### import_error
Whenever there is a fatal error in a running import. After receiving this the import will not continue.
```
{
type: 'import_error',
import_id: '7324830525419355',
error: "Error string"
}
```
### gekko_new
Whenever a new Gekko has been started.
```
{
"type": "gekko_new",
"id": "2018-07-03-16-37-watcher-938815758693549",
"state": {
"mode": "realtime",
"config": {
// the complete config that was passed
},
"id": "2018-07-03-16-37-watcher-938815758693549",
"type": "watcher",
"logType": "watcher",
"active": true,
"stopped": false,
"errored": false,
"errorMessage": false,
"events": {
"initial": {},
"latest": {}
},
"start": "2018-07-03T08:37:51.965Z"
}
}
```
### gekko_event
Whenever a gekko instance has a new Gekko event. See the [gekko events doc](../events.md) for a list of all possible events and details.
```
{
"type": "gekko_event",
"id": "2018-07-03-16-37-watcher-938815758693549",
"event": {
"type": "candle",
"payload": {
"start": "2018-07-03T08:38:00.000Z",
"open": 6623.00000066,
"high": 6623.00000066,
"low": 6623.00000066,
"close": 6623.00000066,
"vwp": 6623.00000066,
"volume": 0,
"trades": 0
}
}
}
```
### gekko_stopped
Whenever a Gekko has been stopped, does not fire when the instance had a fatal error. For that see `gekko_error`.
```
{
"type": "gekko_stopped",
"id": "2018-07-03-16-37-watcher-938815758693549"
}
```
### gekko_error
Whenever a gekko received a fatal error and crashed.
```
{
"type": "gekko_error",
"id": "2018-07-03-16-37-watcher-938815758693549",
"error": "Error message"
}
```
### gekko_archived
Whenever the server does not consider the instance to be relevant anymore, fires after a gekko has been stopped or had a fatal error. After this event the gekko instance is placed in an in memory archive. It will stay here stale (as it won't be updated) until it's deleted.
```
{
"type": "gekko_stopped",
"id": "2018-07-03-16-37-watcher-938815758693549"
}
```
### gekko_deleted
Whenever an archived gekko instance got deleted.
```
{
"type": "gekko_stopped",
"id": "2018-07-03-16-37-watcher-938815758693549"
}
```