Still in very early stages of development. Leveraging the talib
library, via the NPM talib
wrapper.
Following a concept of timeframes with strategies, which look for scenarios (definable sets of conditions over a given number of data frames) on a combination of chart datapoints and/or technical analysis; with subscriptions for firing events (such as buy, sell, SL, etc.), based on a definable number of signals within a given timeframe.
- Planning a candidate release for March 2024.
- YAML playbook templates to configure environments, and execute callbacks
- Spot trading only (could expand on this later)
- In-progress
- Expand storage interfacing (File, Memory, Redis, MongoDB, etc)
- Support for Web3 exchanges
- Testing: Mock JSON
- D3 UI
Bot instances can be configured using YAML templates, known as playbooks, stored in the ~/playbook/<name>/<name>.yml
directory. Replace <name>
with actual template name.
In this example; A subscription
callback action
function will be imported from ~/playbook/<name>/<name>.ts
Without the YML file extension.
npm run playbook <name>
See ~/playbook/eth-btc-mockup/eth-btc-mockup.yml
for a very simple example playbook, which would sell bearish overbought and buy bullish oversold RSI conditions of ETH/BTC, on Kraken.
The concept of items, refers to all core components of the bot. Items are listed in order of dependency.
Item | Description |
---|---|
Analysis |
Provides contexts of configured technical analysis |
Asset |
Identifies individual assets across the ecosystem |
Exchange |
Interface with external exchanges (i.e. Kraken , Uniswap , etc.) |
Pair |
Two Asset items, tied to an Exchange , tracking balances, prices |
Order |
Provides actionable context on a Pair |
Chart |
Manage dataset information for a Pair |
Scenario |
A set of conditions, against Chart and/or Analysis data |
Strategy |
Collection of Scenario against a Chart |
Timeframe |
Collection of Strategy within time constraints |
Subscription |
Collection of Timeframe , awaiting a set of signal conditions, to do actions (callbacks) |
See ~/playbook/eth-btc-mockup/eth-btc-mockup.ts
for an example set of callbacks, reference in the eth-btc-mockup
playbook above
All time values are in milliseconds, with the following exceptions;
ChartData.closeTime
andChartData.openTime
are stored in seconds.- Minutes are used when storing datasets. i.e.
240
for four hours;storage/dataset/Kraken/ETHBTC/2023/03/18/240/
Notations s,m,h,d,w
(i.e. 5m
for five minutes in milliseconds) are available for better readability on Time
(i.e. intervalTime
) suffixed fields, otherwise values are treated as milliseconds.
chart:
ethBtcKraken4h:
pair: ethBtcKraken
pollTime: 5m # five minutes; 300000 milliseconds
candleTime: 4h # four hours; 14400000 milliseconds
Quantities will always be stored as literal values, unless the quantity is a percentage value. In which case, it will operate under the follow conditions;
Side | Last Qty. | Operation |
---|---|---|
Buy |
0 |
Percentage of Balance B |
Buy |
> 0 |
Change current order quantity, by this percentage |
Sell |
0 |
Percentage of Balance A |
Sell |
> 0 |
Change current order quantity, by this percentage |
Is defined in order of what information is available.
- Can be set directly
Chart.datasetNextTime
- When a dataset is added; moves to
Chart.endTime
- Now, minus
Timeframe.windowTime
- If available;
Chart.datasetUpdateTime
- Otherwise; now, minus
Chart.candleTime
multiplied byBOT_CHART_DEFAULT_TOTAL_CANDLE
(default 50)
Finally, Chart.candleTime
is deducted from the time to ensure integrity of any existing candle delta on dataset.
All items are identified in playbooks with a name
(names are only unique to item type), which is then used to link items together.
The example below defines two assets; BTC
and USD
, the exchange Kraken
, and a Pair
, which consists of both assets, on the exchange. This is to allow price tracking, for these assets, specific to Kraken.
See the Items table above for more details on how items are related.
asset:
btc:
symbol: BTC
usd:
symbol: USD
exchange:
kraken:
# More exchanges are in development; Binance, Coinbase, including decentralised options, such as Uniswap
class: Kraken
pair:
btcUsdKraken:
a: btc
b: usd
exchange: kraken
When defining scenarios, we're looking for at least one condition (you can define as many as you need), across one or more candles.
Each condition can target either Chart
candle metrics, or any associated Analytic
.
In the example below, we're looking for the scenario where the RSI is moving to the upside, from at or below a value of 30
(oversold) on the previous candle, to the latest (current) candle, with an RSI value above 30
, where the candles current price (we use close, as it's the latest reading, until the candle closes) is 5%
higher than the previous candle close.
Alternatively, you can also use fixed values, instead of percentages.
Example YAML templates can be found (more to be added) in: ~/playbook/
analysis:
rsi14:
config:
inRealField: close
optInTimePeriod: 14
type: RSI
scenario:
# This is the name of the scenario, and would be used as a reference in strategies
rsi14BullishOversold:
# You'll need to define, and include any analysis below, if you're using it in the conditions below
analysis:
- rsi14
condition:
# Previous candle
-
# Condition 1 - RSI was below 30
- [rsi14.outReal, '<', 30]
# Latest candle
-
# Condition 1 - RSI is now 30 or higher
- [rsi14.outReal, '>=', 30]
# Condition 2 - price is also 5% higher than the previous candle close
- [candle.close, '>=', 5%]
# Or a fixed price, when the price is 42K or higher
# - [candle.close, '>=', 42000]
If you define condition fields without prefixes (i.e outReal
instead of rsi14.outReal
for analysis named rsi14
), the condition will be evaluated on all datasets that use that field name.
Use the candle.
prefix to target only chart candle metrics. Available fields; close
, closeTime
, high
, low
, open
, openTime
, tradeCount
, volume
, vwap
analysis:
ema21:
config:
inRealField: close
optInTimePeriod: 21
type: EMA
sma20:
config:
inRealField: close
optInTimePeriod: 20
type: SMA
scenario:
# EMA21 crossing below the SMA20
bearishCrossBullMarketSupportBand:
analysis:
- ema21
- sma20
condition:
- # Previous candle - TIP: If this candle is removed, then the scenario could be used to indicate and trigger other strategies, while bullish, instead of a cross
- [ema21.outReal, '>=', sma20.outReal]
- # Latest candle
- [ema21.outReal, '<', sma20.outReal]
windowTime: 4w
# EMA21 crossing above SMA20
bullishCrossBullMarketSupportBand:
analysis:
- ema21
- sma20
condition:
- # Previous candle
- [ema21.outReal, '<', sma20.outReal]
- # Latest candle
- [ema21.outReal, '>=', sma20.outReal]
windowTime: 4w
See .env.example
for bot configuration options, and exchange API keys
Mocha, Chai unit test coverage. Currently tests a known dataset for strategy scenarios, against two timeframes.
npm test
tsc --watch
If you'd like to support, and see more time dedicated to the development of this project; donations will allow me to do that, and are greatly appreciated.
bc1qjzxdlf0w8dn3uvr2q7d4htqzg9fx3zs66shlht
0x18cbb0b7Cf158042C9A9e660189Db76Ec0604370
Here is a basic overview of how the bot is currently structured. Subject to change, as this project is still in development.
Available condition
values
high
for the timeframe with the most amount of signalslow
for the timeframe with the least amount of signalsnew
for any previously unseen signals (depends on state data passed with aSubscription.despatch
)total
for the sum of all timeframe signals
Subscription.new({
action: (
subscribe: SubscriptionData
) => {},
chart: chartKrakenEthBtc4h,
condition: [
['total', '>=', '3'],
],
match: 'new', // Or `all`
name: 'buyEthBtcKraken',
timeframeAny: [
defaultTimeframe,
],
});
Run over intervalTime
, checking one or more Strategy
. Matches will Subscription.despatch()
to any Timeframe
subscribers.
let defaultTimeframe = Timeframe.new({
intervalTime: 1000, // 1 second
windowTime: 86400000 * 30, // last 30 days
strategy: [
stratBullishSma20Cross,
],
});
setTimeout(function () {
defaultTimeframe.deactivate();
}, 2000);
One or more Analysis
result sets, for a given Chart
, looking for one or more Scenario
condition matches (which can trigger an optional chained Strategy
).
let stratBullishSma20Cross = Strategy.new({
action: [
[scenarioSma20BullishCross],
],
analysis: [
analysisSma20,
],
chart: chartKrakenEthBtc4h,
name: 'BullishSma20Cross',
});
One or more sets of conditions against one or more sets of Analysis
and/or Chart
metrics.
const Sma20BullishCross = Scenario.new({
analysis: [
analysisSma20,
],
condition: [
// Three candles back
[
['close', '<', 'outReal'],
],
// Two...
[
['close', '<', 'outReal'],
],
// Previous candle
[
['close', '>=', 'outReal'],
],
// Latest candle
[
['close', '>=', 'outReal'],
],
],
name: 'scenarioSma20BullishCross',
});
A light talib
wrapper, with configuration.
const analysisSma20 = Analysis.new({
name: 'SMA20',
config: {
inRealField: 'close',
optInTimePeriod: 20,
// startIndex: 20, // Force offset of TA, to chart datapoints
},
type: 'SMA',
});
Collection of data points for a Chart
with Pair
of Asset
, for a candleTime
, updated every pollTime
, sourced from storage.
let chartKrakenEthBtc4h = Chart.new({
exchange: exchangeKraken,
pair: pairEthBtc,
pollTime: 300000, // 5 minutes in milliseconds
candleTime: 14400000 // 4 hours in milliseconds
});
TBC
let assetEth = Asset.new({
exchange: exchangeKraken,
symbol: 'ETH'
});
let assetBtc = Asset.new({
exchange: exchangeKraken,
symbol: 'BTC'
});
let pairEthBtc = Pair.new({
a: assetEth,
b: assetBtc
});
A potential source of Chart
data, or destination for Exchange
actions. I.e. based on a Subscription
despatch to open/close a Position
.
Support for web3 RPC nodes, will be added.
const exchangeKraken = Exchange.new({
class: 'Kraken',
key: process.env.KRAKEN_CLIENT_KEY,
secret: process.env.KRAKEN_CLIENT_SECRET,
});
All created items (i.e. Pair.new()
) are kept in a simple global storage system, identified by their own UUID. Using Bot.setItem(object): uuid
and Bot.getItem(uuid): object