Welcome, Guest |
You have to register before you can post on our site.
|
Online Users |
There are currently 141 online users. » 1 Member(s) | 140 Guest(s) jerinjohnseo
|
Latest Threads |
Gekko development status ...
Forum: Announcements
Last Post: kontho
7 hours ago
» Replies: 1,006
» Views: 931,002
|
Gekko with malware spotte...
Forum: Announcements
Last Post: Dstewarts
7 hours ago
» Replies: 189
» Views: 170,079
|
Gekko 0.6 released
Forum: Announcements
Last Post: Pharagon
11-23-2024, 10:13 AM
» Replies: 122
» Views: 269,022
|
An official Gekko service...
Forum: Announcements
Last Post: drivemad2
11-22-2024, 07:24 AM
» Replies: 103
» Views: 189,816
|
New Gekko UI in the works
Forum: Announcements
Last Post: clduplicateremover
11-18-2024, 08:21 PM
» Replies: 174
» Views: 227,675
|
How to Soft Reset or Hard...
Forum: General Discussion
Last Post: lucifar
10-07-2021, 07:18 PM
» Replies: 22
» Views: 53,009
|
How to add Binance Future...
Forum: Technical Support
Last Post: Xavier32
10-07-2021, 02:20 PM
» Replies: 47
» Views: 108,371
|
Bittrex Configuration hel...
Forum: Bittrex
Last Post: yirzolusto
10-07-2021, 07:39 AM
» Replies: 6
» Views: 19,115
|
[Question] Why does gekko...
Forum: General Discussion
Last Post: cryptocurrency0
10-06-2021, 01:16 PM
» Replies: 16
» Views: 45,823
|
a couple of technical Que...
Forum: Technical Support
Last Post: mtom78632
10-06-2021, 11:08 AM
» Replies: 25
» Views: 58,576
|
|
|
StochRSI K&D Value |
Posted by: sartux - 04-05-2018, 02:42 PM - Forum: Strategy Development
- No Replies
|
|
I would like to create a simple strategy to buy and sell at the intersection of the K and D curves of the StochRSI (a simple difference between the values and then to attach an IF)
But I can not find where to get these values from gekko, can someone help me?
|
|
|
[BOUNTY] strategy on 4ema |
Posted by: lucag74 - 04-05-2018, 08:26 AM - Forum: Strategy Development
- Replies (4)
|
|
Hi,
my first post here, i'm a newbie in gekko strategy.
What i need , also paying it's a people help me to develop my strategy,
First signal to buy :
Name: 4ema
We analyze 4 Ema,
for example
Blue Ema : 8 (very short)
Green Ema : 13 (short)
Yellow EMA : 20 (medium)
Red EMA : 30 (long)
Of course the time of for ema must can be set as parameters.
Buy signal : upward trend
Blue Ema > Green Ema > Yellow Ema > Red Ema
Sell signal :
When there is no more buy signal
You can see the indicator on tradingview is called 4ema.
This strategy must be implemented in future with other indicator like RSI.
And last question, gekko can be make short sell ? I intend short sell , selling borrowed crypto to buy back then.
Thank's
|
|
|
Kraken import error: (getTrades) returned an irrecoverable error |
Posted by: xFFFFF - 04-05-2018, 08:20 AM - Forum: Technical Support
- No Replies
|
|
In debug all is fine, candles are imported but in terminal I have error like this:
Code: 2018-04-05 10:16:53 (ERROR): [kraken.js] (getTrades) returned an irrecoverable error: Cannot read property 'date' of undefined
2018-04-05 10:16:53 (ERROR): There was an error importing from Kraken [kraken.js] Cannot read property 'date' of undefined
my config
Code: var config = {};
config.debug = true;
config.watch = {
exchange: 'kraken',
currency: 'USD',
asset: 'DASH',
}
config.tradingAdvisor = {
enabled: false,
method: 'BBRSI',
candleSize: 1,
historySize: 2,
}
config.paperTrader = {
enabled: false,
reportInCurrency: true,
simulationBalance: {
asset: 0,
currency: 4,
},
feeMaker: 0.05,
feeTaker: 0.05,
feeUsing: 'maker',
slippage: 0.5,
}
config.performanceAnalyzer = {
enabled: false,
riskFreeReturn: 5
}
config.trader = {
enabled: false,
key: '',
secret: '',
username: '',
passphrase: '',
orderUpdateDelay: 1,
}
config.adviceLogger = {
enabled: false,
muteSoft: true
}
config.candleWriter = {
enabled: true
}
config.adviceWriter = {
enabled: false,
muteSoft: true,
}
config.adapter = 'sqlite';
config.sqlite = {
path: 'plugins/sqlite',
dataDirectory: 'history',
version: 0.1,
dependencies: []
}
config.backtest = {
daterange: 'scan',
batchSize: 50
}
config.importer = {
daterange: {
from: "2018-03-28 00:00",
to: "2018-04-05 08:16:16"
}
}
config['I understand that Gekko only automates MY OWN trading strategies'] = true;
module.exports = config;
|
|
|
Can incrase signature chars limit? |
Posted by: xFFFFF - 04-05-2018, 08:04 AM - Forum: General Discussion
- No Replies
|
|
I would add links to my repos but lenght is too high...
Quote:Please correct the following errors before continuing:
- You cannot update your signature because it is too long. The maximum length for signatures is 100 characters.
- Please remove 122 characters and try again.
|
|
|
Fix Increase efficiency and shorten order filling time |
Posted by: xFFFFF - 04-05-2018, 07:59 AM - Forum: Guides
- No Replies
|
|
I found this solution at Gekkos Issues. It bounce last bid/ask price down/up by 0,04% while making order at Binance. Its cheaper solution than market order type. Im lame in Gekkos functions and overall javascript, so it propablly bounce price two times.
Code: const moment = require('moment');
const _ = require('lodash');
const util = require('../core/util');
const Errors = require('../core/error');
const log = require('../core/log');
const marketData = require('./binance-markets.json');
const Binance = require('binance');
var Trader = function(config) {
_.bindAll(this);
if (_.isObject(config)) {
this.key = config.key;
this.secret = config.secret;
this.currency = config.currency.toUpperCase();
this.asset = config.asset.toUpperCase();
}
this.pair = this.asset + this.currency;
this.name = 'binance';
this.market = _.find(Trader.getCapabilities().markets, (market) => {
return market.pair[0] === this.currency && market.pair[1] === this.asset
});
this.binance = new Binance.BinanceRest({
key: this.key,
secret: this.secret,
timeout: 15000,
recvWindow: 60000, // suggested by binance
disableBeautification: false,
handleDrift: true,
});
};
var retryCritical = {
retries: 10,
factor: 1.2,
minTimeout: 1 * 1000,
maxTimeout: 30 * 1000
};
var retryForever = {
forever: false,
factor: 1.2,
minTimeout: 10 * 1000,
maxTimeout: 30 * 1000
};
var recoverableErrors = new RegExp(/(SOCKETTIMEDOUT|TIMEDOUT|CONNRESET|CONNREFUSED|NOTFOUND|Error -1021|Response code 429|Response code 5)/);
Trader.prototype.processError = function(funcName, error) {
if (!error) return undefined;
if (!error.message || !error.message.match(recoverableErrors)) {
log.error(`[binance.js] (${funcName}) returned an irrecoverable error: ${error}`);
return new Errors.AbortError('[binance.js] ' + error.message || error);
}
log.debug(`[binance.js] (${funcName}) returned an error, retrying: ${error}`);
return new Errors.RetryError('[binance.js] ' + error.message || error);
};
Trader.prototype.handleResponse = function(funcName, callback) {
return (error, body) => {
if (body && !_.isEmpty(body.code)) {
error = new Error(`Error ${body.code}: ${body.msg}`);
}
return callback(this.processError(funcName, error), body);
}
};
Trader.prototype.getTrades = function(since, callback, descending) {
var processResults = function(err, data) {
if (err) return callback(err);
var parsedTrades = [];
_.each(
data,
function(trade) {
parsedTrades.push({
tid: trade.aggTradeId,
date: moment(trade.timestamp).unix(),
price: parseFloat(trade.price),
amount: parseFloat(trade.quantity),
});
},
this
);
if (descending) callback(null, parsedTrades.reverse());
else callback(undefined, parsedTrades);
};
var reqData = {
symbol: this.pair,
};
if (since) {
var endTs = moment(since)
.add(1, 'h')
.valueOf();
var nowTs = moment().valueOf();
reqData.startTime = moment(since).valueOf();
reqData.endTime = endTs > nowTs ? nowTs : endTs;
}
let handler = (cb) => this.binance.aggTrades(reqData, this.handleResponse('getTrades', cb));
util.retryCustom(retryForever, _.bind(handler, this), _.bind(processResults, this));
};
Trader.prototype.getPortfolio = function(callback) {
var setBalance = function(err, data) {
log.debug(`[binance.js] entering "setBalance" callback after api call, err: ${err} data: ${JSON.stringify(data)}`)
if (err) return callback(err);
var findAsset = function(item) {
return item.asset === this.asset;
}
var assetAmount = parseFloat(_.find(data.balances, _.bind(findAsset, this)).free);
var findCurrency = function(item) {
return item.asset === this.currency;
}
var currencyAmount = parseFloat(_.find(data.balances, _.bind(findCurrency, this)).free);
if (!_.isNumber(assetAmount) || _.isNaN(assetAmount)) {
log.error(
`Binance did not return portfolio for ${this.asset}, assuming 0.`
);
assetAmount = 0;
}
if (!_.isNumber(currencyAmount) || _.isNaN(currencyAmount)) {
log.error(
`Binance did not return portfolio for ${this.currency}, assuming 0.`
);
currencyAmount = 0;
}
var portfolio = [
{ name: this.asset, amount: assetAmount },
{ name: this.currency, amount: currencyAmount },
];
return callback(undefined, portfolio);
};
let handler = (cb) => this.binance.account({}, this.handleResponse('getPortfolio', cb));
util.retryCustom(retryForever, _.bind(handler, this), _.bind(setBalance, this));
};
// This uses the base maker fee (0.1%), and does not account for BNB discounts
Trader.prototype.getFee = function(callback) {
var makerFee = 0.05;
callback(undefined, makerFee / 100);
};
Trader.prototype.getTicker = function(callback) {
var setTicker = function(err, data) {
log.debug(`[binance.js] entering "getTicker" callback after api call, err: ${err} data: ${(data || []).length} symbols`);
if (err) return callback(err);
var findSymbol = function(ticker) {
return ticker.symbol === this.pair;
}
var result = _.find(data, _.bind(findSymbol, this));
var ticker = {
ask: parseFloat(result.askPrice),
bid: parseFloat(result.bidPrice),
};
callback(undefined, ticker);
};
let handler = (cb) => this.binance._makeRequest({}, this.handleResponse('getTicker', cb), 'api/v1/ticker/allBookTickers');
util.retryCustom(retryForever, _.bind(handler, this), _.bind(setTicker, this));
};
// Effectively counts the number of decimal places, so 0.001 or 0.234 results in 3
Trader.prototype.getPrecision = function(tickSize) {
if (!isFinite(tickSize)) return 0;
var e = 1, p = 0;
while (Math.round(tickSize * e) / e !== tickSize) { e *= 10; p++; }
return p;
};
Trader.prototype.roundAmount = function(amount, tickSize) {
var precision = 100000000;
var t = this.getPrecision(tickSize);
if(Number.isInteger(t))
precision = Math.pow(10, t);
amount *= precision;
amount = Math.floor(amount);
amount /= precision;
return amount;
};
Trader.prototype.getLotSize = function(tradeType, amount, price, callback) {
log.debug(price);
log.debug(price);
amount = this.roundAmount(amount, this.market.minimalOrder.amount);
if (amount < this.market.minimalOrder.amount)
return callback(undefined, { amount: 0, price: 0 });
log.debug(price);
price = this.roundAmount(price, this.market.minimalOrder.price)
price += (tradeType === 'buy') ? (price * .004) : -(price * .004);
price = Math.max(this.roundAmount(price, 0.00001), 0.00001);
if (price < this.market.minimalOrder.price)
return callback(undefined, { amount: 0, price: 0 });
if (amount * price < this.market.minimalOrder.order)
return callback(undefined, { amount: 0, price: 0});
callback(undefined, { amount: amount, price: price });
}
Trader.prototype.addOrder = function(tradeType, amount, price, callback) {
log.debug(`[binance.js] (addOrder) ${tradeType.toUpperCase()} ${amount} ${this.asset} @${price} ${this.currency}`);
log.debug(price);
price += (tradeType === 'buy') ? (price * .004) : -(price * .004);
price = Math.max(this.roundAmount(price, 0.00001), 0.00001);
log.debug(price);
var setOrder = function(err, data) {
log.debug(`[binance.js] entering "setOrder" callback after api call, err: ${err} data: ${JSON.stringify(data)}`);
if (err) return callback(err);
var txid = data.orderId;
log.debug(`[binance.js] added order with txid: ${txid}`);
callback(undefined, txid);
};
let reqData = {
symbol: this.pair,
side: tradeType.toUpperCase(),
type: 'LIMIT',
timeInForce: 'GTC', // Good to cancel (I think, not really covered in docs, but is default)
quantity: amount,
price: price,
timestamp: new Date().getTime()
};
let handler = (cb) => this.binance.newOrder(reqData, this.handleResponse('addOrder', cb));
util.retryCustom(retryCritical, _.bind(handler, this), _.bind(setOrder, this));
log.debug(price);
log.debug(price);
};
Trader.prototype.getOrder = function(order, callback) {
var get = function(err, data) {
log.debug(`[binance.js] entering "getOrder" callback after api call, err ${err} data: ${JSON.stringify(data)}`);
if (err) return callback(err);
log.debug(price);
var price = parseFloat(data.price);
log.debug(price);
var amount = parseFloat(data.executedQty);
// Data.time is a 13 digit millisecon unix time stamp.
// https://momentjs.com/docs/#/parsing/unix-timestamp-milliseconds/
var date = moment(data.time);
callback(undefined, { price, amount, date });
}.bind(this);
let reqData = {
symbol: this.pair,
orderId: order,
};
let handler = (cb) => this.binance.queryOrder(reqData, this.handleResponse('getOrder', cb));
util.retryCustom(retryCritical, _.bind(handler, this), _.bind(get, this));
};
Trader.prototype.buy = function(amount, price, callback) {
log.debug(price);
this.addOrder('buy', amount, price, callback);
price += price * .004;
};
Trader.prototype.sell = function(amount, price, callback) {
log.debug(price);
log.debug(price);
this.addOrder('sell', amount, price, callback);
price += - price * .004;
};
Trader.prototype.checkOrder = function(order, callback) {
var check = function(err, data) {
log.debug(`[binance.js] entering "checkOrder" callback after api call, err ${err} data: ${JSON.stringify(data)}`);
if (err) return callback(err);
var stillThere = data.status === 'NEW' || data.status === 'PARTIALLY_FILLED';
var canceledManually = data.status === 'CANCELED' || data.status === 'REJECTED' || data.status === 'EXPIRED';
callback(undefined, !stillThere && !canceledManually);
};
let reqData = {
symbol: this.pair,
orderId: order,
};
let handler = (cb) => this.binance.queryOrder(reqData, this.handleResponse('checkOrder', cb));
util.retryCustom(retryCritical, _.bind(handler, this), _.bind(check, this));
};
Trader.prototype.cancelOrder = function(order, callback) {
// callback for cancelOrder should be true if the order was already filled, otherwise false
var cancel = function(err, data) {
log.debug(`[binance.js] entering "cancelOrder" callback after api call, err ${err} data: ${JSON.stringify(data)}`);
if (err) {
if(data && data.msg === 'UNKNOWN_ORDER') { // this seems to be the response we get when an order was filled
return callback(true); // tell the thing the order was already filled
}
return callback(err);
}
callback(undefined);
};
let reqData = {
symbol: this.pair,
orderId: order,
};
let handler = (cb) => this.binance.cancelOrder(reqData, this.handleResponse('cancelOrder', cb));
util.retryCustom(retryForever, _.bind(handler, this), _.bind(cancel, this));
};
Trader.prototype.initMarkets = function(callback) {
}
Trader.getCapabilities = function() {
return {
name: 'Binance',
slug: 'binance',
currencies: marketData.currencies,
assets: marketData.assets,
markets: marketData.markets,
requires: ['key', 'secret'],
providesHistory: 'date',
providesFullHistory: true,
tid: 'tid',
tradable: true,
};
};
module.exports = Trader;
Only lines 215-216, 223-224, 292 and 300 was changed. This same way You can implement fix on all exchanges.
UPDATE - BITFINEX EXAMPLE
You must add one line to Trader.prototype.buy and Trader.prototype.sell in bitfinex.js
Example:
Code: Trader.prototype.buy = function(amount, price, callback) {
this.submit_order('buy', amount, price, callback);
price += price * .004;
}
Trader.prototype.sell = function(amount, price, callback) {
this.submit_order('sell', amount, price, callback);
price += - price * .004;
}
It plus 0,4% of price to ask/bid price on making order to exchange. So incrase/decrase price a bit. Full changed file:
Code: const Bitfinex = require("bitfinex-api-node");
const _ = require('lodash');
const moment = require('moment');
const util = require('../core/util');
const Errors = require('../core/error');
const log = require('../core/log');
const marketData = require('./bitfinex-markets.json');
var Trader = function(config) {
_.bindAll(this);
if(_.isObject(config)) {
this.key = config.key;
this.secret = config.secret;
}
this.name = 'Bitfinex';
this.balance;
this.price;
this.asset = config.asset;
this.currency = config.currency;
this.pair = this.asset + this.currency;
this.bitfinex = new Bitfinex(this.key, this.secret, { version: 1 }).rest;
}
var retryCritical = {
retries: 10,
factor: 1.2,
minTimeout: 10 * 1000,
maxTimeout: 60 * 1000
};
var retryForever = {
forever: true,
factor: 1.2,
minTimeout: 10 * 1000,
maxTimeout: 300 * 1000
};
// Probably we need to update these string
var recoverableErrors = new RegExp(/(SOCKETTIMEDOUT|TIMEDOUT|CONNRESET|CONNREFUSED|NOTFOUND|429|443|5\d\d)/g);
Trader.prototype.processError = function(funcName, error) {
if (!error) return undefined;
if (!error.message.match(recoverableErrors)) {
log.error(`[bitfinex.js] (${funcName}) returned an irrecoverable error: ${error.message}`);
return new Errors.AbortError('[bitfinex.js] ' + error.message);
}
log.debug(`[bitfinex.js] (${funcName}) returned an error, retrying: ${error.message}`);
return new Errors.RetryError('[bitfinex.js] ' + error.message);
};
Trader.prototype.handleResponse = function(funcName, callback) {
return (error, data, body) => {
return callback(this.processError(funcName, error), data);
}
};
Trader.prototype.getPortfolio = function(callback) {
let process = (err, data) => {
if (err) return callback(err);
// We are only interested in funds in the "exchange" wallet
data = data.filter(c => c.type === 'exchange');
const asset = _.find(data, c => c.currency.toUpperCase() === this.asset);
const currency = _.find(data, c => c.currency.toUpperCase() === this.currency);
let assetAmount, currencyAmount;
if(_.isObject(asset) && _.isNumber(+asset.available) && !_.isNaN(+asset.available))
assetAmount = +asset.available;
else {
log.error(`Bitfinex did not provide ${this.asset} amount, assuming 0`);
assetAmount = 0;
}
if(_.isObject(currency) && _.isNumber(+currency.available) && !_.isNaN(+currency.available))
currencyAmount = +currency.available;
else {
log.error(`Bitfinex did not provide ${this.currency} amount, assuming 0`);
currencyAmount = 0;
}
const portfolio = [
{ name: this.asset, amount: assetAmount },
{ name: this.currency, amount: currencyAmount },
];
callback(undefined, portfolio);
};
let handler = (cb) => this.bitfinex.wallet_balances(this.handleResponse('getPortfolio', cb));
util.retryCustom(retryForever, _.bind(handler, this), _.bind(process, this));
}
Trader.prototype.getTicker = function(callback) {
let process = (err, data) => {
if (err) return callback(err);
// whenever we reach this point we have valid
// data, the callback is still the same since
// we are inside the same javascript scope.
callback(undefined, {bid: +data.bid, ask: +data.ask})
};
let handler = (cb) => this.bitfinex.ticker(this.pair, this.handleResponse('getTicker', cb));
util.retryCustom(retryForever, _.bind(handler, this), _.bind(process, this));
}
// This assumes that only limit orders are being placed, so fees are the
// "maker fee" of 0.1%. It does not take into account volume discounts.
Trader.prototype.getFee = function(callback) {
var makerFee = 0.1;
callback(undefined, makerFee / 100);
}
Trader.prototype.submit_order = function(type, amount, price, callback) {
let process = (err, data) => {
if (err) return callback(err);
callback(err, data.order_id);
}
amount = Math.floor(amount*100000000)/100000000;
let handler = (cb) => this.bitfinex.new_order(this.pair,
amount + '',
price + '',
this.name.toLowerCase(),
type,
'exchange limit',
this.handleResponse('submitOrder', cb)
);
util.retryCustom(retryCritical, _.bind(handler, this), _.bind(process, this));
}
Trader.prototype.buy = function(amount, price, callback) {
this.submit_order('buy', amount, price, callback);
price += price * .004;
}
Trader.prototype.sell = function(amount, price, callback) {
this.submit_order('sell', amount, price, callback);
price += - price * .004;
}
Trader.prototype.checkOrder = function(order_id, callback) {
let process = (err, data) => {
if (err) return callback(err);
callback(undefined, !data.is_live);
}
let handler = (cb) => this.bitfinex.order_status(order_id, this.handleResponse('checkOrder', cb));
util.retryCustom(retryCritical, _.bind(handler, this), _.bind(process, this));
}
Trader.prototype.getOrder = function(order_id, callback) {
let process = (err, data) => {
if (err) return callback(err);
var price = parseFloat(data.avg_execution_price);
var amount = parseFloat(data.executed_amount);
var date = moment.unix(data.timestamp);
callback(undefined, {price, amount, date});
};
let handler = (cb) => this.bitfinex.order_status(order_id, this.handleResponse('getOrder', cb));
util.retryCustom(retryCritical, _.bind(handler, this), _.bind(process, this));
}
Trader.prototype.cancelOrder = function(order_id, callback) {
let process = (err, data) => {
if (err) return callback(err);
return callback(undefined);
}
let handler = (cb) => this.bitfinex.cancel_order(order_id, this.handleResponse('cancelOrder', cb));
util.retryCustom(retryForever, _.bind(handler, this), _.bind(process, this));
}
Trader.prototype.getTrades = function(since, callback, descending) {
let process = (err, data) => {
if (err) return callback(err);
var trades = _.map(data, function(trade) {
return {
tid: trade.tid,
date: trade.timestamp,
price: +trade.price,
amount: +trade.amount
}
});
callback(undefined, descending ? trades : trades.reverse());
};
var path = this.pair;
if(since)
path += '?limit_trades=2000';
let handler = (cb) => this.bitfinex.trades(path, this.handleResponse('getTrades', cb));
util.retryCustom(retryForever, _.bind(handler, this), _.bind(process, this));
}
Trader.getCapabilities = function () {
return {
name: 'Bitfinex',
slug: 'bitfinex',
currencies: marketData.currencies,
assets: marketData.assets,
markets: marketData.markets,
requires: ['key', 'secret'],
tid: 'tid',
providesFullHistory: true,
providesHistory: 'date',
tradable: true,
forceReorderDelay: true
};
}
module.exports = Trader;
My subjective feelings are that it speeds up filling orders a bit. The more value you put in place .004 the faster theoretically it should be order filled. Im using tickrate 2 sec and orderdelay 15 sec. If someone will compare the method with the traditional one in live mode, please let me know.
This idea can be used to delevop a more intelligent solution that would raise the price until the order is filled. I would be grateful if someone did it
|
|
|
Complete Gekko's datasets - ready files to download and use |
Posted by: xFFFFF - 04-04-2018, 10:14 PM - Forum: General Discussion
- Replies (22)
|
|
Ready to use Gekko's SQLite dumps files. Without importing via Gekko import and exchange APIs.
Just copy the file to the history directory and you have: full history of Binance Exchange for example. The files are updated daily after 23:15 GMT.
Included
- Binance - FULL history
- Poloniex - all pairs - in progress
- Kraken - all pairs - in progress
Download
Links and all acctually information are on Github: https://github.com/xFFFFF/Gekko-Datasets
Soon
- Kraken all pairs
- Bitfinex all pairs
- Poloniex all pairs
- Gdax all pairs
How to import pairs from Coinfalcon, BTCC and Bitstamp?
|
|
|
Add multi-threaded backtesting |
Posted by: tommiehansen - 04-04-2018, 01:23 PM - Forum: Technical Discussion
- Replies (1)
|
|
Why?
Because a single backtest does not really say that much, often we want to test a broad range of different parameters but doing this takes a lot of bloody time.
Imagine that one of these tests take 5 minutes and now imagine that you want to try at least 10 different variations. It quickly becomes so tedious so that one basically needs to create 3rd party software in order to do this.
How?
1. Make sure Gekko caches repeating calculations (basically -- just cache last X requests so that repeating queries for the same data is cached or 'pre-compiled')
2. Add options for the above (i might run 3x strategies against 3x different asset/currencies so i might need more caching)
3. Invent a new pseudo-TOML format to allow dynamic parameters
4. Add timeouts
5. Add option for number of threads
6. Let user specify timeout @ web/vue/UIconfig.js (this file is btw terrible since it dictates timeouts for the backtesting ... should be a user.conf value and easily change:able via the api e.g. { timeout: 30000 }
7. Add option for multi-server mode (run the backtests against an array of servers instead of just 'localhost')
8. Use localStorage to automatically save stuff (not fun to have to input the same stuff again... again.. and again)
There are loads of things to write here, basically -- check out my "GAB" tool:
https://forum.gekko.wizb.it/thread-56589.html
And basically clone the functionality and core ideas.
|
|
|
|