#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
####
source "${COLORIZE_SH_SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE:-${0}}" )" && pwd )}/Compatibility/compatibility.sh"
# Escape codes
COLORIZER_START=${COLORIZER_START:="\033["}
COLORIZER_END=${COLORIZER_END:="m"}
# Default colors
COLORIZER_blue=${COLORIZER_blue:="0;34"}
COLORIZER_green=${COLORIZER_green:="0;32"}
COLORIZER_cyan=${COLORIZER_cyan:="0;36"}
COLORIZER_red=${COLORIZER_red:="0;31"}
COLORIZER_purple=${COLORIZER_purple:="0;35"}
COLORIZER_yellow=${COLORIZER_yellow:="0;33"}
COLORIZER_gray=${COLORIZER_gray:="1;30"}
COLORIZER_light_blue=${COLORIZER_light_blue:="1;34"}
COLORIZER_light_green=${COLORIZER_light_green:="1;32"}
COLORIZER_light_cyan=${COLORIZER_light_cyan:="1;36"}
COLORIZER_light_red=${COLORIZER_light_red:="1;31"}
COLORIZER_light_purple=${COLORIZER_light_purple:="1;35"}
COLORIZER_light_yellow=${COLORIZER_light_yellow:="1;33"}
COLORIZER_light_gray=${COLORIZER_light_gray:="0;37"}
# Somewhat special colors
COLORIZER_black=${COLORIZER_black:="0;30"}
COLORIZER_white=${COLORIZER_white:="1;37"}
COLORIZER_none=${COLORIZER_none:="0"}
##
# Parse the input and return the ansi code output processed output
##
COLORIZER_process_input() {
local prompt_option="${1}"
local strip_option="${2}"
shift 2
local processed="${*}"
local pseudoTag=""
local stack
ARRAY_define "stack"
local result=""
local ansiToken=""
result="${processed%%<*}"
if [ "${result}" != "" ] && [ "${result}" != "${processed}" ]; then
# Cut outer content, which has been processed already
processed="<${processed#*<}"
fi
while [ "${processed#*<}" != "${processed}" ]; do
# Isolate first tag in stream
pseudoTag="${processed#*<}"
pseudoTag="${pseudoTag%%>*}"
# Push/Pop tag to/from stack
if [ "${pseudoTag:0:1}" != "/" ]; then
ARRAY_push "stack" "${pseudoTag}"
else
if [ "${pseudoTag:1}" != "$(ARRAY_peek "stack")" ]; then
echo "Mismatching colorize tag nesting at <$(ARRAY_peek "stack")>...<${pseudoTag}>"
exit 42
fi
ARRAY_pop "stack" >/dev/null
fi
# Apply ansi formatting
if [ -z "${strip_option}" ]; then
pseudoTag="${pseudoTag/-/_}"
if [ "${pseudoTag:0:1}" != "/" ]; then
# Opening Tag
eval "ansiToken=\"\${COLORIZER_${pseudoTag}}\""
else
# Closing Tag
if [ "$(ARRAY_count "stack")" -eq 0 ]; then
ansiToken="${COLORIZER_none}"
else
eval "ansiToken=\"\${COLORIZER_$(ARRAY_peek "stack")}\""
fi
fi
# Add escape codes
ansiToken="${COLORIZER_START}${ansiToken}${COLORIZER_END}"
if [ "${prompt_option}" = "SET" ]; then
ansiToken="\[${ansiToken}\]"
fi
result="${result}${ansiToken}"
fi
# Cut processed portion from stream
processed="${processed#*>}"
# Update result with next content part
result="${result}${processed%%<*}"
done
if [ "$(ARRAY_count "stack")" -ne 0 ]; then
echo "Could not find closing tag for <$(ARRAY_peek "stack")>"
exit 42
fi
result="${result//</<}"
result="${result//>/>}"
echo "${result}"
}
##
# Parse a given colorize string and output the correctly escaped ansi-code
# formatted string for it.
#
# This function is the only public API method to this utillity
#
# echo -e is used for output.
#
# The -n option may be specified, which will behave exactly like echo -n, aka
# omitting the newline.
#
# To use ansi in a prompt without behaving badly, using the -p option.
#
# @option -n omit the newline
# @option -p escape ansi for prompt usage
# @option -s instead of replacing with ansi, just strip the tags
# @param [string,...]
##
colorize() {
local OPTIND=1
local newline_option=""
local prompt_option=""
local strip_option=""
local option=""
while getopts ":nps" option; do
case "${option}" in
n) newline_option="SET";;
p) prompt_option="SET";;
s) strip_option="SET";;
\?) echo "Invalid option (-${OPTARG}) given to colorize"; exit 42;;
esac
done
shift $((OPTIND-1))
local processed_message="$(COLORIZER_process_input "${prompt_option}" "${strip_option}" "${@}")"
if [ "${newline_option}" = "SET" ]; then
echo -en "${processed_message}"
else
echo -e "${processed_message}"
fi
}
# Allow alternate spelling
alias colourise=colorize
================================================
FILE: cli/imports/common.sh
================================================
#!/bin/bash
# colors
red=$'\e[1;31m'
grn=$'\e[1;32m'
yel=$'\e[1;33m'
blu=$'\e[1;34m'
mag=$'\e[1;35m'
cyn=$'\e[1;36m'
end=$'\e[0m'
# upload to transer.sh
# use: transer "$file"
transfer() {
if [ $# -eq 0 ];
then echo -e "No arguments specified. Usage:\necho transfer /tmp/test.md\ncat /tmp/test.md | transfer test.md";
return 1;
fi
tmpfile=$( mktemp -t transferXXX );
if tty -s; then basefile=$(basename "$1" | sed -e 's/[^a-zA-Z0-9._-]/-/g');
curl --progress-bar --upload-file "$1" "https://transfer.sh/$basefile" >> $tmpfile;
else curl --progress-bar --upload-file "-" "https://transfer.sh/$1" >> $tmpfile ;
fi;
echo "Your file: ";
cat $tmpfile;
file=$(cat $tmpfile);
cat > $outputDir/last.txt <<< $file
rm -f $tmpfile;
}
================================================
FILE: cli/lastupload/last.txt
================================================
https://transfer.sh/FrW09/sync.tar.gz
================================================
FILE: cli/upload.sh
================================================
#!/bin/bash
clear
# ------------------------------
#
# UPLOAD GEKKO HISTORY DATA
# To transfer.sh + get link
#
# -------------------------------
# imports
source imports/common.sh
source imports/colorizer.sh
# check config.sh
if [ ! -f config.sh ]; then
colorize "ERROR config.sh could not be found, copy config.sample.sh and modify to suit your needs!\n"
return
fi
# import user config
source config.sh
# create output dir
outputDir="lastupload"
mkdir -p $outputDir
# dir
historyDir="$gekkoDir/history"
echo
colorize "COMPRESSING HISTORY DIRECTORY \n---\nDestination folder: $outputDir\n"
colorize "Please wait, it might take a while...\n"
# compress
tar -czf "$outputDir/sync.tar.gz" $historyDir
# msg
colorize "Compression completed.\n"
colorize "UPLOADING TO TRANSFER.SH \n---\n"
# upload
transfer "$outputDir/sync.tar.gz"
colorize "\n\nCompleted.\n"
colorize "Saved lastfile src to: $outputDir/last.txt\n"
# remove old compressed file
rm -rf "$outputDir/sync.tar.gz"
================================================
FILE: strategies/RSI_BULL_BEAR.js
================================================
/*
RSI Bull and Bear
Use different RSI-strategies depending on a longer trend
3 feb 2017
(CC-BY-SA 4.0) Tommie Hansen
https://creativecommons.org/licenses/by-sa/4.0/
*/
// req's
var log = require ('../core/log.js');
var config = require ('../core/util.js').getConfig();
// strategy
var strat = {
/* INIT */
init: function()
{
this.name = 'RSI Bull and Bear';
this.requiredHistory = config.tradingAdvisor.historySize;
this.resetTrend();
// debug? set to flase to disable all logging/messages (improves performance)
this.debug = false;
// performance
config.backtest.batchSize = 1000; // increase performance
config.silent = true;
config.debug = false;
// add indicators
this.addIndicator('maSlow', 'SMA', this.settings.SMA_long );
this.addIndicator('maFast', 'SMA', this.settings.SMA_short );
this.addIndicator('BULL_RSI', 'RSI', { interval: this.settings.BULL_RSI });
this.addIndicator('BEAR_RSI', 'RSI', { interval: this.settings.BEAR_RSI });
// debug stuff
this.startTime = new Date();
this.stat = {
bear: { min: 100, max: 0 },
bull: { min: 100, max: 0 }
};
}, // init()
/* RESET TREND */
resetTrend: function()
{
var trend = {
duration: 0,
direction: 'none',
longPos: false,
};
this.trend = trend;
},
/* get lowest/highest for backtest-period */
lowHigh: function( rsi, type )
{
let cur;
if( type == 'bear' ) {
cur = this.stat.bear;
if( rsi < cur.min ) this.stat.bear.min = rsi; // set new
if( rsi > cur.max ) this.stat.bear.max = rsi;
}
else {
cur = this.stat.bull;
if( rsi < cur.min ) this.stat.bull.min = rsi; // set new
if( rsi > cur.max ) this.stat.bull.max = rsi;
}
},
/* CHECK */
check: function()
{
// get all indicators
let ind = this.indicators,
maSlow = ind.maSlow.result,
maFast = ind.maFast.result,
rsi;
// BEAR TREND
if( maFast < maSlow )
{
rsi = ind.BEAR_RSI.result;
if( rsi > this.settings.BEAR_RSI_high ) this.short();
else if( rsi < this.settings.BEAR_RSI_low ) this.long();
if(this.debug) this.lowHigh( rsi, 'bear' );
//log.debug('BEAR-trend');
}
// BULL TREND
else
{
rsi = ind.BULL_RSI.result;
if( rsi > this.settings.BULL_RSI_high ) this.short();
else if( rsi < this.settings.BULL_RSI_low ) this.long();
if(this.debug) this.lowHigh( rsi, 'bull' );
//log.debug('BULL-trend');
}
}, // check()
/* LONG */
long: function()
{
if( this.trend.direction !== 'up' ) // new trend? (only act on new trends)
{
this.resetTrend();
this.trend.direction = 'up';
this.advice('long');
//log.debug('go long');
}
if(this.debug)
{
this.trend.duration++;
log.debug ('Long since', this.trend.duration, 'candle(s)');
}
},
/* SHORT */
short: function()
{
// new trend? (else do things)
if( this.trend.direction !== 'down' )
{
this.resetTrend();
this.trend.direction = 'down';
this.advice('short');
}
if(this.debug)
{
this.trend.duration++;
log.debug ('Short since', this.trend.duration, 'candle(s)');
}
},
/* END backtest */
end: function(){
let seconds = ((new Date()- this.startTime)/1000),
minutes = seconds/60,
str;
minutes < 1 ? str = seconds + ' seconds' : str = minutes + ' minutes';
log.debug('====================================');
log.debug('Finished in ' + str);
log.debug('====================================');
if(this.debug)
{
let stat = this.stat;
log.debug('RSI low/high for period');
log.debug('BEAR low/high: ' + stat.bear.min + ' / ' + stat.bear.max);
log.debug('BULL low/high: ' + stat.bull.min + ' / ' + stat.bull.max);
}
}
};
module.exports = strat;
================================================
FILE: strategies/RSI_BULL_BEAR.toml
================================================
# SMA Trends
SMA_long = 1000
SMA_short = 50
# BULL
BULL_RSI = 10
BULL_RSI_high = 80
BULL_RSI_low = 60
# BEAR
BEAR_RSI = 15
BEAR_RSI_high = 50
BEAR_RSI_low = 20
# BULL/BEAR is defined by the longer SMA trends
# if SHORT over LONG = BULL
# if SHORT under LONG = BEAR
================================================
FILE: strategies/RSI_BULL_BEAR_ADX.js
================================================
/*
RSI Bull and Bear + ADX modifier
1. Use different RSI-strategies depending on a longer trend
2. But modify this slighly if shorter BULL/BEAR is detected
-
(CC-BY-SA 4.0) Tommie Hansen
https://creativecommons.org/licenses/by-sa/4.0/
-
NOTE: Requires custom indicators found here:
https://github.com/Gab0/Gekko-extra-indicators
(c) Gabriel Araujo
Howto: Download + add to gekko/strategies/indicators
*/
// req's
var log = require('../core/log.js');
var config = require('../core/util.js').getConfig();
// strategy
var strat = {
/* INIT */
init: function()
{
// core
this.name = 'RSI Bull and Bear + ADX';
this.requiredHistory = config.tradingAdvisor.historySize;
this.resetTrend();
// debug? set to false to disable all logging/messages/stats (improves performance in backtests)
this.debug = false;
// performance
config.backtest.batchSize = 1000; // increase performance
config.silent = true; // NOTE: You may want to set this to 'false' @ live
config.debug = false;
// SMA
this.addIndicator('maSlow', 'SMA', this.settings.SMA.long );
this.addIndicator('maFast', 'SMA', this.settings.SMA.short );
// RSI
this.addIndicator('BULL_RSI', 'RSI', { interval: this.settings.BULL.rsi });
this.addIndicator('BEAR_RSI', 'RSI', { interval: this.settings.BEAR.rsi });
// ADX
this.addIndicator('ADX', 'ADX', this.settings.ADX.adx );
// MOD (RSI modifiers)
this.BULL_MOD_high = this.settings.BULL.mod_high;
this.BULL_MOD_low = this.settings.BULL.mod_low;
this.BEAR_MOD_high = this.settings.BEAR.mod_high;
this.BEAR_MOD_low = this.settings.BEAR.mod_low;
// debug stuff
this.startTime = new Date();
// add min/max if debug
if( this.debug ){
this.stat = {
adx: { min: 1000, max: 0 },
bear: { min: 1000, max: 0 },
bull: { min: 1000, max: 0 }
};
}
/* MESSAGES */
// message the user about required history
log.info("====================================");
log.info('Running', this.name);
log.info('====================================');
log.info("Make sure your warmup period matches SMA_long and that Gekko downloads data if needed");
// warn users
if( this.requiredHistory < this.settings.SMA.long )
{
log.warn("*** WARNING *** Your Warmup period is lower then SMA_long. If Gekko does not download data automatically when running LIVE the strategy will default to BEAR-mode until it has enough data.");
}
}, // init()
/* RESET TREND */
resetTrend: function()
{
var trend = {
duration: 0,
direction: 'none',
longPos: false,
};
this.trend = trend;
},
/* get low/high for backtest-period */
lowHigh: function( val, type )
{
let cur;
if( type == 'bear' ) {
cur = this.stat.bear;
if( val < cur.min ) this.stat.bear.min = val; // set new
else if( val > cur.max ) this.stat.bear.max = val;
}
else if( type == 'bull' ) {
cur = this.stat.bull;
if( val < cur.min ) this.stat.bull.min = val; // set new
else if( val > cur.max ) this.stat.bull.max = val;
}
else {
cur = this.stat.adx;
if( val < cur.min ) this.stat.adx.min = val; // set new
else if( val > cur.max ) this.stat.adx.max = val;
}
},
/* CHECK */
check: function()
{
// get all indicators
let ind = this.indicators,
maSlow = ind.maSlow.result,
maFast = ind.maFast.result,
rsi,
adx = ind.ADX.result;
// BEAR TREND
// NOTE: maFast will always be under maSlow if maSlow can't be calculated
if( maFast < maSlow )
{
rsi = ind.BEAR_RSI.result;
let rsi_hi = this.settings.BEAR.high,
rsi_low = this.settings.BEAR.low;
// ADX trend strength?
if( adx > this.settings.ADX.high ) rsi_hi = rsi_hi + this.BEAR_MOD_high;
else if( adx < this.settings.ADX.low ) rsi_low = rsi_low + this.BEAR_MOD_low;
if( rsi > rsi_hi ) this.short();
else if( rsi < rsi_low ) this.long();
if(this.debug) this.lowHigh( rsi, 'bear' );
}
// BULL TREND
else
{
rsi = ind.BULL_RSI.result;
let rsi_hi = this.settings.BULL.high,
rsi_low = this.settings.BULL.low;
// ADX trend strength?
if( adx > this.settings.ADX.high ) rsi_hi = rsi_hi + this.BULL_MOD_high;
else if( adx < this.settings.ADX.low ) rsi_low = rsi_low + this.BULL_MOD_low;
if( rsi > rsi_hi ) this.short();
else if( rsi < rsi_low ) this.long();
if(this.debug) this.lowHigh( rsi, 'bull' );
}
// add adx low/high if debug
if( this.debug ) this.lowHigh( adx, 'adx');
}, // check()
/* LONG */
long: function()
{
if( this.trend.direction !== 'up' ) // new trend? (only act on new trends)
{
this.resetTrend();
this.trend.direction = 'up';
this.advice('long');
if( this.debug ) log.info('Going long');
}
if( this.debug )
{
this.trend.duration++;
log.info('Long since', this.trend.duration, 'candle(s)');
}
},
/* SHORT */
short: function()
{
// new trend? (else do things)
if( this.trend.direction !== 'down' )
{
this.resetTrend();
this.trend.direction = 'down';
this.advice('short');
if( this.debug ) log.info('Going short');
}
if( this.debug )
{
this.trend.duration++;
log.info('Short since', this.trend.duration, 'candle(s)');
}
},
/* END backtest */
end: function()
{
let seconds = ((new Date()- this.startTime)/1000),
minutes = seconds/60,
str;
minutes < 1 ? str = seconds.toFixed(2) + ' seconds' : str = minutes.toFixed(2) + ' minutes';
log.info('====================================');
log.info('Finished in ' + str);
log.info('====================================');
// print stats and messages if debug
if(this.debug)
{
let stat = this.stat;
log.info('BEAR RSI low/high: ' + stat.bear.min + ' / ' + stat.bear.max);
log.info('BULL RSI low/high: ' + stat.bull.min + ' / ' + stat.bull.max);
log.info('ADX min/max: ' + stat.adx.min + ' / ' + stat.adx.max);
}
}
};
module.exports = strat;
================================================
FILE: strategies/RSI_BULL_BEAR_ADX.toml
================================================
[SMA]
long = 1000
short = 50
[BULL]
rsi = 10
high = 80
low = 60
mod_high = 5
mod_low = -5
[BEAR]
rsi = 15
high = 50
low = 20
mod_high = 15
mod_low = -5
[ADX]
adx = 3
high = 70
low = 50
================================================
FILE: strategies/TEMA.js
================================================
/*
TEMA
Triple EMA strategy with 'safety net'
---
Uses 1x TEMA to go long/short if short trend is over TEMA.
On top of this it uses a longer SMA as a safety net and simple
stays out of the market if short SMA is under that SMA.
---
The general idea is to buy in good market conditions and simply not
be a part of longer downwards trends.
*/
// req's
var log = require ('../core/log.js');
var config = require ('../core/util.js').getConfig();
// strategy
var strat = {
/* INIT */
init: function()
{
// base
this.name = 'TEMA';
this.requiredHistory = config.tradingAdvisor.historySize;
this.debug = false; // outputs messages, set to false to increase performance
// add indicators and reset trend
this.resetTrend();
this.addTulipIndicator('maSlow', 'tema', { optInTimePeriod: this.settings.long });
this.addTulipIndicator('maFast', 'sma', { optInTimePeriod: this.settings.short });
// check if long SMA is to be used
if( this.settings.SMA_long > 0 )
{
this.useSafety = true;
this.addTulipIndicator('maSlowest', 'sma', { optInTimePeriod: this.settings.SMA_long });
}
// set startTime to measure execution time @ end()
this.startTime = new Date();
}, // init()
/* RESET TREND */
resetTrend: function()
{
var trend = {
duration: 0,
direction: 'none',
longPos: false,
};
this.trend = trend;
}, // resetTrend()
/* CHECK */
check: function()
{
// do nothing if we don't got enough history
if( this.candle.close.length < this.requiredHistory ) return;
// fetch indicators
let ti = this.tulipIndicators;
let maFast = ti.maFast.result.result,
maSlow = ti.maSlow.result.result;
// check if safety option > 0
if( this.useSafety )
{
let maSlowest = ti.maSlowest.result.result;
if( maSlow < maSlowest )
{
this.short();
return; // quit
}
}
// other rules
if( maFast > maSlow ) { this.long(); }
else if( maFast < maSlow ) { this.short(); }
}, // check()
/* LONG */
long: function()
{
if( this.trend.direction !== 'up' )
{
this.resetTrend();
this.trend.direction = 'up';
this.advice('long');
}
if( this.debug )
{
this.trend.duration++;
log.debug ('Positive since', this.trend.duration, 'candle(s)');
}
},
/* SHORT */
short: function()
{
if( this.trend.direction !== 'down' )
{
this.resetTrend();
this.trend.direction = 'down';
this.advice('short');
}
if( this.debug )
{
this.trend.duration++;
log.debug ('Negative since', this.trend.duration, 'candle(s)');
}
},
/* END */
end: function()
{
let seconds = ((new Date()- this.startTime)/1000),
minutes = seconds/60,
str;
minutes < 1 ? str = seconds + ' seconds' : str = minutes + ' minutes';
log.debug('Finished in ' + str);
}
}; // strat{}
/* EXPORT */
module.exports = strat;
================================================
FILE: strategies/TEMA.toml
================================================
# Short / Long (EMA/TEMA)
short = 10
long = 80
# Safety (SMA, 0 = disable)
SMA_long = 200
================================================
FILE: syncAll/config.sample.sh
================================================
#!/bin/bash
# Gekko directory
# Relative -or- absolute to where you have gekko tools installed
gDir='../../gekko'
================================================
FILE: syncAll/download.sh
================================================
#!/bin/bash
clear
### Download sync files @ ./sync/last.txt and replace files in Gekko with these new files ###
# colors
grn=$'\e[1;32m'
yel=$'\e[1;33m'
mag=$'\e[1;35m'
cyn=$'\e[1;36m'
end=$'\e[0m'
# check config.sh
if [ ! -f config.sh ]; then
printf "${red}ERROR${end} config.sh could not be found, copy config.sample.sh and modify to suit your needs!\n"
return
fi
# import user config ($gDir)
source config.sh
outputDir="sync"
# get latest file from github
git pull
file=$(cat $outputDir/last.txt)
saveFile='sync.tar.gz';
# get $filename function
get() {
if [ $# -eq 0 ];
then echo -e "No arguments specified.";
return 1;
fi
echo
echo
curl "$1" >> $saveFile;
}
# get the file
printf "Downloading file ${yel}$file${end}, please stand by...";
get $file
printf "\n\n"
# untar
printf "Unpacking ${yel}$saveFile${end}...\n\n"
tar -xvzf $saveFile
echo
# sync new > old (and replace)
printf "Replacing old with new @ ${yel}gekko/ > $gDir ${end}\n\n"
rsync -ah gekko/* $gDir
echo
# remove crap
rm -rf gekko
rm -rf sync.tar.gz
printf "${grn}Completed.${end}\n\n"
================================================
FILE: syncAll/sync/last.txt
================================================
https://transfer.sh/AKPh1/sync.tar.gz
================================================
FILE: syncAll/upload.sh
================================================
#!/bin/bash
clear
# colors
red=$'\e[1;31m'
grn=$'\e[1;32m'
yel=$'\e[1;33m'
blu=$'\e[1;34m'
mag=$'\e[1;35m'
cyn=$'\e[1;36m'
end=$'\e[0m'
# check config.sh
if [ ! -f config.sh ]; then
printf "${red}ERROR${end} config.sh could not be found, copy config.sample.sh and modify to suit your needs!\n"
return
fi
# import user config ($gDir)
source config.sh
outputDir="sync"
mkdir -p $outputDir
# dir string
DIRS="$gDir/strategies $gDir/config"
# ask user if history should be included or not
read -p "${yel}Include history?${end} [y/n]: " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]
then
DIRS+=" $gDir/history"
echo "${cyn}OK -- including history${end}"
fi
echo
printf "Compressing the files/folders ${yel}$DIRS${end} \nDestination folder: ${yel}$outputDir${end}\n"
printf "${grn}Please wait...${end}\n\n"
# compress
tar -czf "$outputDir/sync.tar.gz" $DIRS
echo
printf "${yel}Compression completed.${end}\n\n"
# upload to transer.sh
transfer() {
if [ $# -eq 0 ];
then echo -e "No arguments specified. Usage:\necho transfer /tmp/test.md\ncat /tmp/test.md | transfer test.md";
return 1;
fi
tmpfile=$( mktemp -t transferXXX );
if tty -s; then basefile=$(basename "$1" | sed -e 's/[^a-zA-Z0-9._-]/-/g');
curl --progress-bar --upload-file "$1" "https://transfer.sh/$basefile" >> $tmpfile;
else curl --progress-bar --upload-file "-" "https://transfer.sh/$1" >> $tmpfile ;
fi;
echo "Your file: ";
cat $tmpfile;
file=$(cat $tmpfile);
cat > $outputDir/last.txt <<< $file
rm -f $tmpfile;
}
printf "${grn}Uploading to transfer.sh, please wait...${end}\n\n"
transfer "$outputDir/sync.tar.gz"
printf "\n"
printf "${yel}Done.${end}\n\n"
printf "Saved lastfile src to: ${yel}$outputDir/last.txt${end}\n\n"
# remove old compressed file
rm -rf "$outputDir/sync.tar.gz"
================================================
FILE: temp/system/functions.php
================================================
]*?(\/?)>/i",'<$1$2>', $str);
return $str;
}
# prp: + print_r
function prp($str, $color = ''){ echo ''; print_r($str); echo '
'; }
function prph($str){
echo '=======================================
';
echo ''; print_r($str); echo '
';
echo '=======================================
';
}
# get all files in a dir
function listFiles( $dir ){
$files = @array_diff(scandir($dir), array('.', '..', '.gitignore'));
if( !$files ) $files = 'Error: No files reside within the directory ' . $dir;
return $files;
}
# contains
# sample: if( contains('something', $source) ){ /* string 'something' existed in $source */ }
function contains($needle, $haystack) {
return strpos($haystack, $needle) !== false;
}
# rtrim + ltrim
function rmspace($str){
$data = rtrim(ltrim($str, ' '), ' ');
$data = str_replace(" ", '', $data);
return $data;
}
function numfix($str){
$data = str_replace(',','.',$str);
$data = htmlentities($data);
$data = rmspace($data);
return $data;
}
# date diff
function date_between($a, $b){
$a = new DateTime($a);
$b = new DateTime($b);
return $b->diff($a);
}
# T-date split e.g. 2017-24-12T16:00:00.000Z > 2017-24-12 16:00:00
function tdate($str){
$arr = explode('T', $str);
$date = $arr[0];
$time = explode('.', $arr[1])[0];
return $date .' ' .$time;
}
# convert ms to days, hours etc
function secondsToHuman($str){
$a = new \DateTime('@0');
$b = new \DateTime("@$str");
$diff = $a->diff($b);
if( $diff->days > 0 ){
return $diff->format('%ad, %hh');
}
else {
return $diff->format('%hh');
}
}
# curl get
function curl_get($url)
{
defined(SERVER_TIMEOUT) ? $timeout = SERVER_TIMEOUT : $timeout = 600;
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_ENCODING, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 120);
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
$result = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ( $status != 200 ) {
die("Error: call to URL $url failed with status $status, response $result, curl_error " . curl_error($curl) . ", curl_errno " . curl_errno($curl));
}
curl_close($curl);
return $result;
}
# measure time (simple)
function timer_start(){ $a = microtime(true); return $a; }
function timer_end($start){
$end = microtime(true);
$diff = ($end-$start); // secondsls
$diff = round($diff*100)/100;
// conver to minutes
if( $diff > 65 ) { $diff = round(($diff/60)*10)/10 . 'min'; }
else { $diff = $diff . 's'; } // or just use seconds
return $diff;
}
# output table from query; requires PDO::FETCHASSOC from query result
function sqlTable($res, $class = 'tbl', $echo = true, $id = false ){
$html = '';
$head = $res[0];
if($id) $id = " id='$id'";
$html .= "";
foreach($head as $k=>$v){
$html .= "| $k | ";
}
$html .= "
";
foreach( $res as $key => $val ){
$html .= "";
foreach($head as $i=>$h){
$html .= "| " . $val[$i] . " | ";
}
$html .= "
";
}
$html .= "
";
if($echo) { echo $html; }
else { return $html; }
}
# flatten arrays
function array_flatten( $a, $key=NULL)
{
$r = array();
if(is_array($a))foreach($a as $k=>$v)$r=array_merge($r,array_flatten($v,$k));
else $r[$key]=$a;
return $r;
}
/*-----------------------------------------------------
SIMPLIFIED CURL GET CACHE FUNC
example
curl_cache('http://google.com', 'cache/mycachefile.php', '1 hour');
-----------------------------------------------------*/
function curl_cache($src, $file, $time){
$exists = file_exists($file);
$time = "+" . $time;
$isExternal = false;
if (strpos($src, 'http') !== false) { $isExternal = true; }
// file does not exist or is over x time
if( !$exists || ( $exists && time() > strtotime("$time", filemtime($file))) ) {
if( $isExternal ){
defined(SERVER_TIMEOUT) ? $timeout = SERVER_TIMEOUT : $timeout = 600;
$curl = curl_init($src);
curl_setopt($curl, CURLOPT_ENCODING, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 120);
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept-Encoding: gzip,deflate')); // important -- reduce doc by 90%
$data = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if( $status === 200 ){
file_put_contents( $file, gzencode($data) );
}
curl_close($curl);
} // $isExternal
// not external, is a string of some sort -- so just put it in a file
else {
file_put_contents( $file, gzencode($src) );
}
}
// file exists, just get it
else {
$data = gzdecode( file_get_contents($file) );
}
// return
return $data;
} // curl_cache()
/*-----------------------------------------------------
CURL POST
uri
object with vars {}
-----------------------------------------------------*/
function curl_post($url, $vars)
{
defined(SERVER_TIMEOUT) ? $timeout = SERVER_TIMEOUT : $timeout = 600;
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json",'Accept-Encoding: gzip,deflate'));
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_POSTFIELDS, $vars);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 120);
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
$data = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$arr['data'] = $data;
$arr['status'] = $status;
$arr = (object) $arr;
curl_close($curl);
return $arr;
}
// used to posting to 'self'
function curl_post2($url, $vars)
{
defined(SERVER_TIMEOUT) ? $timeout = SERVER_TIMEOUT : $timeout = 600;
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $vars);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 120);
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
$data = curl_exec($curl);
curl_close($curl);
return $data;
}
function curl_post_cache( $url, $vars, $file, $cacheTime )
{
$exists = file_exists($file);
$time = "+" . $cacheTime;
// file does not exist or is over x time
if( !$exists || ( $exists && time() > strtotime("$time", filemtime($file))) )
{
$data = curl_post($url, $vars);
# only cache file if everything was ok
if( $data->status === 200 ){
file_put_contents( $file, gzencode(json_encode($data)) );
}
}
// file exists, just get it
else {
$data = json_decode(gzdecode(file_get_contents($file)));
}
$data->data = json_decode($data->data);
return $data;
}
?>
================================================
FILE: temp/system/user.config.sample.php
================================================
# TEST
some test
readable date
function timeToDate( $str, $format = 'Y-m-d' ) {
return date($format, $str);
}
/*
min/max date range for a pair
-
get min/max date range and convert to readable date
requires db-handle and table name
-
return array with date_min/date_max
*/
function minMax( $db, $table )
{
$sql = "
SELECT
strftime('%Y-%m-%d %H:%M', datetime(MIN(start), 'unixepoch')) as date_min,
strftime('%Y-%m-%d %H:%M', datetime(MAX(start), 'unixepoch')) as date_max
FROM `$table`
";
$q = $db->query($sql);
$q = $q->fetchAll()[0]; // always just one
return $q;
}
/*
CRITICAL CHECKS
*/
// check if user config exists
if( !file_exists('system/user.config.php') ) die('ERROR Could not find user.config.php, make sure you have createad it.');
require_once 'system/functions.php';
require_once 'system/user.config.php';
// check if the path is correct
if( !file_exists($gekko_path . 'README.md') ) die('ERROR The path to your Gekko install is wrong or not working.');
/*
SETUP PATHS
*/
$gp = $gekko_path;
$paths = [
'gekko' => $gp,
'history' => $gp . 'history/',
];
$paths = json_decode(json_encode($paths));
#prp($paths);
/*
GET ALL HISTORY FILES
*/
$files = listFiles( $paths->history );
// ..then remove any not ending with '.db'
foreach($files as $key => $value)
{
$cur = end(explode('.', $files[$key])); // explode + get last
if( $cur !== 'db' ) unset($files[$key]);
}
$files = array_values($files); // re-index
echo 'history files';
prp($files);
/*
TRY SQLite STUFF
*/
// init $db, TEMP: use first db
$first = $paths->history . $files[0];
$db = new PDO('sqlite:' . $first) or die('ERROR Could not connect to database.');
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$sql = "
SELECT name
FROM main.sqlite_master
WHERE type = 'table'
";
$tables = $db->query($sql);
$tables = $tables->fetchAll();
// filter out tables not containg candles_
foreach( $tables as $key => $val )
{
$cur = $tables[$key];
$name = $val['name'];
if( !contains('candles_', $name) || contains('sqlite', $name) ) unset($tables[$key]);
}
echo 'tables';
prp($tables);
// get min/max
echo 'min/max';
$stuff = minMax($db, $tables[0]['name']);
prp($stuff);
$db = null;
?>
================================================
FILE: wsl-install/gekko_install.sh
================================================
#!/bin/bash
clear
echo "-------------------------------------------"
echo 'INSTALLING GEKKO + DEPENDECIES'
echo '-------------------------------------------'
echo 'This will take a while, go get some coffe'
sleep 3
sudo su
apt-get update -y && apt-upgrade -y && apt-get update -y
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
apt-get install nodejs -y
apt-get install build-essential -y
apt-get install git -y
cd /mnt/c/
mkdir www
cd www
git clone git://github.com/askmike/gekko.git
cd gekko
npm install --only=production
cd exchange
npm install --only=production
cd ..
npm install tulind
apt-get install nano -y
apt-get autoremove -y
node gekko --ui
================================================
FILE: wsl-install/readme.md
================================================
# Install Gekko in Windows bash
##### Prerequisites (required)
* Install Bash on Windows 10:
https://docs.microsoft.com/en-us/windows/wsl/install-win10
* C-drive in Windows (or change all references to c to any other drive you might have)
#### How-to
##### Simple way
1. Open bash
2. curl -sL https://raw.githubusercontent.com/tommiehansen/gekko_tools/master/wsl-install/gekko_install.sh | sudo bash -
##### Manual way
1. open bash (win-key + type 'bash' + ENTER)
2. sudo su
3. apt-get update -y && apt-upgrade -y && apt-get update -y
Above will take some time, expect it to take 10-20 minutes.
4. curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
5. apt-get install nodejs -y
6. apt-get install build-essential -y
7. apt-get install git -y
8. apt-get install jed && apt-get install nano
9. cd /mnt/c/
10. mkdir www
11. cd www
12. git clone git://github.com/askmike/gekko.git
13. cd gekko
14. npm install --only=production
cd exchange
npm install --only=production
cd ..
15. npm install tulind
16. apt-get autoremove -y
17. node gekko --ui