Skip to content

Commit

Permalink
Merge pull request #1161 from Drakkar-Software/dev
Browse files Browse the repository at this point in the history
Dev merge
  • Loading branch information
GuillaumeDSM authored Jan 18, 2024
2 parents e92b36c + 6f262c9 commit cd091ae
Show file tree
Hide file tree
Showing 13 changed files with 144 additions and 15 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ jobs:
echo "S3_API_SECRET_KEY=${{ secrets.S3_API_SECRET_KEY }}" >> $GITHUB_ENV
echo "S3_REGION_NAME=${{ secrets.S3_REGION_NAME }}" >> $GITHUB_ENV
echo "S3_ENDPOINT_URL=${{ secrets.S3_ENDPOINT_URL }}" >> $GITHUB_ENV
echo "CLOUDFLARE_TOKEN=${{ secrets.CLOUDFLARE_TOKEN }}" >> $GITHUB_ENV
echo "CLOUDFLARE_ZONE=${{ secrets.CLOUDFLARE_ZONE }}" >> $GITHUB_ENV
TARGET_BRANCH=$([ "$GITHUB_HEAD_REF" == "" ] && echo ${GITHUB_REF##*/} || echo "$GITHUB_HEAD_REF")
echo "TARGET_BRANCH=${TARGET_BRANCH}" >> $GITHUB_ENV
Expand Down Expand Up @@ -145,6 +147,7 @@ jobs:
sed -i "s/VERSION_PLACEHOLDER/${TARGET_BRANCH#refs/*/}/g" metadata.yaml
cd OctoBot
python start.py tentacles -m "../metadata.yaml" -d "../new_tentacles" -p "../../any_platform.zip" -ite -ute ${{ secrets.TENTACLES_OFFICIAL_PATH }}/tentacles -upe ${{ secrets.TENTACLES_OFFICIAL_PATH }}/packages/full/${{ secrets.TENTACLES_REPOSITORY_NAME }}/
python ../scripts/clear_cloudflare_cache.py ${TARGET_BRANCH#refs/*/}
- name: Publish latest tentacles
if: github.ref == 'refs/heads/dev' && startsWith(github.ref, 'refs/tags') != true
Expand All @@ -154,6 +157,7 @@ jobs:
sed -i "s/VERSION_PLACEHOLDER/latest/g" metadata.yaml
cd OctoBot
python start.py tentacles -m "../metadata.yaml" -d "../new_tentacles" -p "../../any_platform.zip" -upe ${{ secrets.TENTACLES_OFFICIAL_PATH }}/packages/full/${{ secrets.TENTACLES_REPOSITORY_NAME }}/
python ../scripts/clear_cloudflare_cache.py latest
- name: Publish stable tentacles
if: github.ref == 'refs/heads/master'
Expand All @@ -163,6 +167,7 @@ jobs:
sed -i "s/VERSION_PLACEHOLDER/stable/g" metadata.yaml
cd OctoBot
python start.py tentacles -m "../metadata.yaml" -d "../new_tentacles" -p "../../any_platform.zip" -upe ${{ secrets.TENTACLES_OFFICIAL_PATH }}/packages/full/${{ secrets.TENTACLES_REPOSITORY_NAME }}/
python ../scripts/clear_cloudflare_cache.py stable
- name: Publish cleaned branch tentacles
if: startsWith(github.ref, 'refs/tags') != true && github.ref != 'refs/heads/master'
Expand All @@ -175,6 +180,7 @@ jobs:
sed -i "s/officials/dev/g" metadata.yaml
cd OctoBot
python start.py tentacles -m "../metadata.yaml" -d "../new_tentacles" -p "../../any_platform.zip" -upe ${{ secrets.TENTACLES_OFFICIAL_PATH }}/packages/full/${{ secrets.TENTACLES_REPOSITORY_NAME }}/
python ../scripts/clear_cloudflare_cache.py $branch
notify:
if: ${{ failure() }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ <h2>Strategy optimizer in progress</h2>
<i class="fa-regular fa-lightbulb"></i>
If you want to deeply test your strategy, compare its results in different situations and figure out
the best settings for your traded markets, we suggest to check out the
<a href="https://www.octobot.cloud/blog/strategy-designer-revamp?utm_source=octobot&utm_medium=dk&utm_campaign=regular_open_source_content&utm_content=strategy_optimizer" target="_blank" rel="noopener">
<a href="https://www.octobot.cloud/en/blog/strategy-designer-revamp?utm_source=octobot&utm_medium=dk&utm_campaign=regular_open_source_content&utm_content=strategy_optimizer" target="_blank" rel="noopener">
new strategy designer </a>
available on <a href="{{OCTOBOT_COMMUNITY_URL}}/" target="_blank" rel="noopener">
<i class="fa-brands fa-octopus-deploy"></i> octobot.cloud pro plan</a>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ function load_report(report, should_alert=False) {
const url = reportDiv.attr(update_url_attr);
$.get(url, (data) => {
if ("report" in data) {
let error_message = "";
const globalReport = data["report"]
const botReport = globalReport["bot_report"]
report.show();
Expand All @@ -63,15 +64,14 @@ function load_report(report, should_alert=False) {
let profitability = profitabilities.join(", ");
const errors_count = globalReport["errors_count"];
if ("error" in globalReport || errors_count > 0) {
let error_message = "Warning: error(s) during backtesting";
error_message = "Warning: error(s) during backtesting";
if ("error" in globalReport) {
error_message += " " + globalReport["error"];
}
if (errors_count > 0) {
error_message += " " + errors_count + " error(s)";
}
error_message += ", more details in logs.";
profitability = profitability + " " + error_message;
if (should_alert) {
create_alert("error", error_message, "");
}
Expand All @@ -87,7 +87,7 @@ function load_report(report, should_alert=False) {
});
});
const all_profitability = symbol_reports.join(", ");
$("#bProf").html(`${round_digits(profitability, 4)}%`);
$("#bProf").html(`${round_digits(profitability, 4)}% ${error_message}`);
const avg_profitabilities = [];
$.each(botReport["market_average_profitability"], function (exchange, market_average_profitability) {
const exch = show_exchanges ? `${exchange}: ` : "";
Expand Down
2 changes: 1 addition & 1 deletion Services/Interfaces/web_interface/templates/about.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ <h2>Get more from OctoBot using OctoBot cloud</h2>
</li>
<li>
Deploy your OctoBot on the cloud and enjoy your OctoBot from anywhere while benefiting
from cloud exclusive features such as the <a href="https://www.octobot.cloud/blog/strategy-designer-revamp?utm_source=octobot&utm_medium=dk&utm_campaign=regular_open_source_content&utm_content=about" target="_blank" rel="noopener">strategy designer</a>.
from cloud exclusive features such as the <a href="https://www.octobot.cloud/en/blog/strategy-designer-revamp?utm_source=octobot&utm_medium=dk&utm_campaign=regular_open_source_content&utm_content=about" target="_blank" rel="noopener">strategy designer</a>.
</li>
</ul>
<p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ <h2>
<div class="col-12 col-lg-4 col-xl-5 card-text py-3">
<p>
Find more information the recent changes and future plans on
<a href="{{OCTOBOT_COMMUNITY_LANDING_URL}}/blog/introducing-the-new-octobot-cloud?utm_source=octobot&utm_medium=dk&utm_campaign=regular_open_source_content&utm_content=community_blog" target="_blank" rel="noopener"> our blog</a>.
<a href="{{OCTOBOT_COMMUNITY_LANDING_URL}}/en/blog/introducing-the-new-octobot-cloud?utm_source=octobot&utm_medium=dk&utm_campaign=regular_open_source_content&utm_content=community_blog" target="_blank" rel="noopener"> our blog</a>.
</p>
<p>
Explore the OctoBot cloud strategies using the <a href="{{OCTOBOT_COMMUNITY_URL}}/strategies?utm_source=octobot&utm_medium=dk&utm_campaign=regular_open_source_content&utm_content=community_strategies" target="_blank" rel="noopener">strategy explorer</a>.
Expand Down
7 changes: 5 additions & 2 deletions Services/Interfaces/web_interface/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ <h2>
<div id="graph-symbol-price"></div>
</div>
{% if not watched_symbols %}
<div class="card-footer">No watched markets: using a default one. You can add <a href="#"><i class="far fa-star text-white" aria-label="Watched markets star"></i></a> watched markets in the <a href="{{ url_for('trading') }}">trading section</a>.</div>
<div class="card-footer">No watched markets: using a default one. You can add
<a href="#"><i class="far fa-star text-white" aria-label="Watched markets star"></i></a>
watched markets in the <a href="{{ url_for('trading', _anchor='panel-market-status') }}">trading section</a>.
</div>
{% endif %}
{% endif %}
</div>
Expand Down Expand Up @@ -164,7 +167,7 @@ <h2 class="modal-title">Settings</h2>
<input type="checkbox" class="custom-control-input" id="displayOrderToggle" {{'checked' if display_orders}} data-update-url="{{url_for('api.display_config')}}">
<label class="custom-control-label" for="displayOrderToggle">Display orders</label>
</div>
<div class="font-italic">Add and remove watched symbols from the <a href="{{url_for('trading')}}">trading tab</a>.</div>
<div class="font-italic">Add and remove watched symbols from the <a href="{{ url_for('trading', _anchor='panel-market-status') }}">trading tab</a>.</div>
</div>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions Trading/Exchange/coinex_websocket_feed/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .coinex_websocket import CoinexCCXTWebsocketConnector
31 changes: 31 additions & 0 deletions Trading/Exchange/coinex_websocket_feed/coinex_websocket.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Drakkar-Software OctoBot-Tentacles
# Copyright (c) Drakkar-Software, All rights reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3.0 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library.
import octobot_trading.exchanges as exchanges
from octobot_trading.enums import WebsocketFeeds as Feeds
import tentacles.Trading.Exchange.coinex.coinex_exchange as coinex_exchange


class CoinexCCXTWebsocketConnector(exchanges.CCXTWebsocketConnector):
EXCHANGE_FEEDS = {
Feeds.TRADES: True,
Feeds.KLINE: Feeds.UNSUPPORTED.value, # only for swap markets (futures)
Feeds.TICKER: True,
Feeds.CANDLE: Feeds.UNSUPPORTED.value, # only for swap markets (futures)
}

@classmethod
def get_name(cls):
return coinex_exchange.Coinex.get_name()
6 changes: 6 additions & 0 deletions Trading/Exchange/coinex_websocket_feed/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"version": "1.2.0",
"origin_package": "OctoBot-Default-Tentacles",
"tentacles": ["CoinexCCXTWebsocketConnector"],
"tentacles-requirements": []
}
14 changes: 13 additions & 1 deletion Trading/Exchange/kucoin/kucoin_exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,6 @@ async def get_open_orders(self, symbol=None, since=None, limit=None, **kwargs) -
async def get_order(self, exchange_order_id: str, symbol: str = None, **kwargs: dict) -> dict:
return await super().get_order(exchange_order_id, symbol=symbol, **kwargs)

@_kucoin_retrier
async def create_order(self, order_type: trading_enums.TraderOrderType, symbol: str, quantity: decimal.Decimal,
price: decimal.Decimal = None, stop_price: decimal.Decimal = None,
side: trading_enums.TradeOrderSide = None, current_price: decimal.Decimal = None,
Expand All @@ -302,6 +301,19 @@ async def create_order(self, order_type: trading_enums.TraderOrderType, symbol:
side=side, current_price=current_price,
reduce_only=reduce_only, params=params)

# add retried to _create_order_with_retry to avoid catching error in self._order_operation context manager
@_kucoin_retrier
async def _create_order_with_retry(self, order_type, symbol, quantity: decimal.Decimal,
price: decimal.Decimal, stop_price: decimal.Decimal,
side: trading_enums.TradeOrderSide,
current_price: decimal.Decimal,
reduce_only: bool, params) -> dict:
return await super()._create_order_with_retry(
order_type=order_type, symbol=symbol, quantity=quantity, price=price,
stop_price=stop_price, side=side, current_price=current_price,
reduce_only=reduce_only, params=params
)

async def get_position(self, symbol: str, **kwargs: dict) -> dict:
"""
Get the current user symbol position list
Expand Down
21 changes: 15 additions & 6 deletions Trading/Mode/daily_trading_mode/daily_trading.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def init_user_inputs(self, inputs: dict) -> None:
"max_currency_percent", commons_enums.UserInputTypes.FLOAT, 100, inputs,
min_val=0, max_val=100,
title="Maximum currency percent: Maximum portfolio % to allocate on a given currency. "
"Used to compute buy order amounts.",
"Used to compute buy order amounts. Ignored when 'Amount per buy/entry order' is set.",
)

@classmethod
Expand Down Expand Up @@ -186,6 +186,7 @@ class DailyTradingModeConsumer(trading_modes.AbstractTradingModeConsumer):
TAKE_PROFIT_PRICE_KEY = "TAKE_PROFIT_PRICE"
REDUCE_ONLY_KEY = "REDUCE_ONLY"
ORDER_EXCHANGE_CREATION_PARAMS = "ORDER_EXCHANGE_CREATION_PARAMS"
TARGET_PROFIT_MODE_ENTRY_QUANTITY_SIDE = trading_enums.TradeOrderSide.BUY

def __init__(self, trading_mode):
super().__init__(trading_mode)
Expand Down Expand Up @@ -310,8 +311,11 @@ async def _get_buy_limit_quantity_from_risk(self, ctx, eval_note, quantity, quot
if increasing_position and self.BUY_WITH_MAXIMUM_SIZE_ORDERS:
return quantity
# check configured quantity
if user_amount := trading_modes.get_user_selected_order_amount(self.trading_mode,
trading_enums.TradeOrderSide.BUY):
if user_amount := trading_modes.get_user_selected_order_amount(
self.trading_mode,
self.TARGET_PROFIT_MODE_ENTRY_QUANTITY_SIDE
if self.USE_TARGET_PROFIT_MODE else trading_enums.TradeOrderSide.BUY
):
return await script_keywords.get_amount_from_input_amount(
context=ctx,
input_amount=user_amount,
Expand Down Expand Up @@ -352,8 +356,11 @@ async def _get_sell_limit_quantity_from_risk(self, ctx, eval_note, quantity, quo
# check all in orders
if not increasing_position and self.SELL_WITH_MAXIMUM_SIZE_ORDERS:
return quantity
if user_amount := trading_modes.get_user_selected_order_amount(self.trading_mode,
trading_enums.TradeOrderSide.SELL):
if user_amount := trading_modes.get_user_selected_order_amount(
self.trading_mode,
self.TARGET_PROFIT_MODE_ENTRY_QUANTITY_SIDE
if self.USE_TARGET_PROFIT_MODE else trading_enums.TradeOrderSide.SELL
):
return await script_keywords.get_amount_from_input_amount(
context=ctx,
input_amount=user_amount,
Expand Down Expand Up @@ -392,7 +399,9 @@ async def _get_sell_limit_quantity_from_risk(self, ctx, eval_note, quantity, quo

async def _get_market_quantity_from_risk(self, ctx, eval_note, quantity, quote, selling, increasing_position):
# check configured quantity
side = trading_enums.TradeOrderSide.SELL if selling else trading_enums.TradeOrderSide.BUY
side = self.TARGET_PROFIT_MODE_ENTRY_QUANTITY_SIDE if self.USE_TARGET_PROFIT_MODE else (
trading_enums.TradeOrderSide.SELL if selling else trading_enums.TradeOrderSide.BUY
)
if user_amount := trading_modes.get_user_selected_order_amount(self.trading_mode, side):
return await script_keywords.get_amount_from_input_amount(
context=ctx,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1132,9 +1132,11 @@ async def test_target_profit_mode_futures_trading(future_tools):
buy_order.origin_price * (trading_constants.ONE - consumer.TARGET_PROFIT_STOP_LOSS)
)

consumer.trading_mode.trading_config[trading_constants.CONFIG_BUY_ORDER_AMOUNT] = "100q"
# take profit and stop loss / short signal
short_orders = await consumer.create_new_orders(symbol, decimal.Decimal(str(1)), trading_enums.EvaluatorStates.SHORT.value)
sell_order = short_orders[0]
assert sell_order.origin_quantity == decimal.Decimal('0.01426697') # 0.01739031 without 100q config
assert isinstance(sell_order, trading_personal_data.SellLimitOrder)
assert len(sell_order.chained_orders) == 2
take_profit_order = sell_order.chained_orders[1]
Expand Down
59 changes: 59 additions & 0 deletions scripts/clear_cloudflare_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import os
import sys
import requests


CLOUDFLARE_ZONE = os.getenv("CLOUDFLARE_ZONE")
CLOUDFLARE_TOKEN = os.getenv("CLOUDFLARE_TOKEN")
S3_BUCKET_NAME = os.getenv("S3_BUCKET_NAME")


def _send_purge_cache_request(url: str, cloudflare_token: str, urls_to_purge: list):
with requests.post(
url=url,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {cloudflare_token}",
},
json={
"files": urls_to_purge
}
) as resp:
if resp.status_code == 200:
print(f"Cache purged for {', '.join(urls_to_purge)}")
else:
print(f"Error when purging cache, status: {resp.status_code}, body: {resp.text}")


def _get_tentacles_url(tentacle_url_identifier):
if not S3_BUCKET_NAME:
raise RuntimeError("Missing S3_BUCKET_NAME env variable")
return os.getenv(
"TENTACLES_URL",
f"https://{S3_BUCKET_NAME}."
f"{os.getenv('TENTACLES_OCTOBOT_ONLINE_URL', 'octobot.online')}/"
f"officials/packages/full/base/"
f"{tentacle_url_identifier}/"
f"any_platform.zip"
)


def clear_cache(tentacle_url_identifiers):
if not CLOUDFLARE_ZONE:
raise RuntimeError("Missing CLOUDFLARE_ZONE env variable")
if not CLOUDFLARE_TOKEN:
raise RuntimeError("Missing CLOUDFLARE_TOKEN env variable")
# https://developers.cloudflare.com/api/operations/zone-purge#purge-cached-content-by-url
url = f"https://api.cloudflare.com/client/v4/zones/{CLOUDFLARE_ZONE}/purge_cache"
_send_purge_cache_request(
url,
CLOUDFLARE_TOKEN,
[
_get_tentacles_url(tentacle_url_identifier)
for tentacle_url_identifier in tentacle_url_identifiers
]
)


if __name__ == '__main__':
clear_cache(sys.argv[1:])

0 comments on commit cd091ae

Please sign in to comment.