Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ jobs:
python-version: 3.10.x
architecture: x64

- uses: actions/setup-node@v6
with:
node-version: 22

- name: Install dependencies
run: pip install --prefer-binary -r dev_requirements.txt -r requirements.txt

Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ wheels/
.installed.cfg
*.egg

node_modules

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
Expand Down Expand Up @@ -136,6 +138,7 @@ cython_debug/
.env

*.zip
*.db

# tensorboard
tensorboard_logs
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
recursive-include octobot_script/config *.json *.ini
recursive-include octobot_script/resources *.js *.css *.html
recursive-exclude octobot_script/resources/report/node_modules *
recursive-exclude octobot_script/resources/report/src *

include README.md
include LICENSE
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,12 @@ asyncio.run(rsi_test())
We recently created a telegram channel dedicated to OctoBot Script.

[![Telegram News](https://img.shields.io/static/v1?label=Telegram%20chat&message=Join&logo=telegram&&color=007bff&style=for-the-badge)](https://t.me/+366CLLZ2NC0xMjFk)

### Developers

To build report from sources:

```bash
npm install
npm run build

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

```
42 changes: 42 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.8/schema.json",
"assist": { "actions": { "source": { "organizeImports": "on" } } },
"files": {
"includes": [
"**",
"!**/dist/**/*",
"!**/node_modules/**/*",
"!**/src/components/ui/**/*"
]
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noExplicitAny": "off",
"noArrayIndexKey": "off"
},
"style": {
"noNonNullAssertion": "off",
"noParameterAssign": "error",
"useSelfClosingElements": "error",
"noUselessElse": "error"
}
}
},
"formatter": {
"indentStyle": "space"
},
"javascript": {
"formatter": {
"quoteStyle": "double",
"semicolons": "asNeeded"
}
},
"css": {
"parser": {
"tailwindDirectives": true
}
}
}
23 changes: 23 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "octobot_script/resources/report/src/index.css",
"baseColor": "gray",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"rtl": false,
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {}
}
61 changes: 36 additions & 25 deletions example.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
import asyncio
import tulipy # Can be any TA library.
import tulipy # Can be any TA library.
import octobot_script as obs


async def rsi_test():
async def example():
async def initialize(ctx):
# Compute entries only once per backtest.
closes = await obs.Close(ctx, max_history=True)
times = await obs.Time(ctx, max_history=True, use_close_time=True)
rsi_v = tulipy.rsi(closes, period=ctx.tentacle.trading_config["period"])
delta = len(closes) - len(rsi_v)
# Populate entries with timestamps of candles where RSI is
# bellow the "rsi_value_buy_threshold" configuration.
run_data["entries"] = {
times[index + delta]
for index, rsi_val in enumerate(rsi_v)
if rsi_val < ctx.tentacle.trading_config["rsi_value_buy_threshold"]
}
await obs.plot_indicator(ctx, "RSI", times[delta:], rsi_v, run_data["entries"])

async def strategy(ctx):
# Will be called at each candle.
if run_data["entries"] is None:
# Compute entries only once per backtest.
closes = await obs.Close(ctx, max_history=True)
times = await obs.Time(ctx, max_history=True, use_close_time=True)
rsi_v = tulipy.rsi(closes, period=ctx.tentacle.trading_config["period"])
delta = len(closes) - len(rsi_v)
# Populate entries with timestamps of candles where RSI is
# bellow the "rsi_value_buy_threshold" configuration.
run_data["entries"] = {
times[index + delta]
for index, rsi_val in enumerate(rsi_v)
if rsi_val < ctx.tentacle.trading_config["rsi_value_buy_threshold"]
}
await obs.plot_indicator(ctx, "RSI", times[delta:], rsi_v, run_data["entries"])
# Called at each candle.
# Uses pre-computed entries times to enter positions when relevant.
# Also, instantly set take profits and stop losses.
# Position exits could also be set separately.
if obs.current_live_time(ctx) in run_data["entries"]:
# Uses pre-computed entries times to enter positions when relevant.
# Also, instantly set take profits and stop losses.
# Position exists could also be set separately.
await obs.market(ctx, "buy", amount="10%", stop_loss_offset="-15%", take_profit_offset="25%")
await obs.market(
ctx,
"buy",
amount="10%",
stop_loss_offset="-15%",
take_profit_offset="25%",
)

# Configuration that will be passed to each run.
# It will be accessible under "ctx.tentacle.trading_config".
Expand All @@ -34,19 +41,23 @@ async def strategy(ctx):
}

# Read and cache candle data to make subsequent backtesting runs faster.
data = await obs.get_data("BTC/USDT", "1d", start_timestamp=1505606400)
data = await obs.get_data(
"BTC/USDT", "1d", start_timestamp=1505606400, social_services=[]
)
run_data = {
"entries": None,
}
# Run a backtest using the above data, strategy and configuration.
res = await obs.run(data, strategy, config)
res = await obs.run(
data, config, initialize_func=initialize, strategy_func=strategy
)
print(res.describe())
# Generate and open report including indicators plots
await res.plot(show=True)
await obs.generate_and_show_report(res)
# Stop data to release local databases.
await data.stop()


# Call the execution of the script inside "asyncio.run" as
# OctoBot-Script runs using the python asyncio framework.
asyncio.run(rsi_test())
asyncio.run(example())
Loading