-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Trading][Mode] Add SocialSignalHandlerTradingMode
- Loading branch information
Showing
6 changed files
with
208 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .social_signal_handler_trading import SocialSignalHandlerTradingMode |
12 changes: 12 additions & 0 deletions
12
Trading/Mode/social_signal_handler_trading_mode/config/SocialSignalHandlerTradingMode.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"default_config": [ | ||
"SimpleStrategyEvaluator" | ||
], | ||
"required_strategies": [ | ||
"SimpleStrategyEvaluator", | ||
"TechnicalAnalysisStrategyEvaluator" | ||
], | ||
"required_strategies_min_count": 1, | ||
"sell_with_maximum_size_orders": false, | ||
"buy_with_maximum_size_orders": false | ||
} |
16 changes: 16 additions & 0 deletions
16
...Mode/social_signal_handler_trading_mode/config/SocialSignalHandlerTradingMode_schema.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"type": "object", | ||
"title": "SignalCatcherTradingMode", | ||
"properties": { | ||
"sell_with_maximum_size_orders": { | ||
"title": "All in sell trades: Trade with all available funds at each sell order.", | ||
"type": "boolean", | ||
"format": "checkbox" | ||
}, | ||
"buy_with_maximum_size_orders": { | ||
"title": "All in buy trades: Trade with all available funds at each buy order.", | ||
"type": "boolean", | ||
"format": "checkbox" | ||
} | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
Trading/Mode/social_signal_handler_trading_mode/metadata.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"version": "1.2.0", | ||
"origin_package": "OctoBot-Default-Tentacles", | ||
"tentacles": ["SocialSignalHandlerTradingMode"], | ||
"tentacles-requirements": ["mixed_strategies_evaluator"] | ||
} |
1 change: 1 addition & 0 deletions
1
.../social_signal_handler_trading_mode/resources/SocialSignalHandlerTradingMode.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
SocialSignalHandlerTradingMode is a trading mode that buys social signals and instantly places take profit orders. |
172 changes: 172 additions & 0 deletions
172
Trading/Mode/social_signal_handler_trading_mode/social_signal_handler_trading.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
# 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 decimal | ||
|
||
import octobot_commons.pretty_printer as pretty_printer | ||
import async_channel.constants as channel_constants | ||
|
||
import octobot_trading.personal_data as trading_personal_data | ||
import octobot_trading.enums as trading_enums | ||
import octobot_trading.modes as trading_modes | ||
import octobot_trading.constants as trading_constants | ||
import octobot_trading.exchange_channel as exchanges_channel | ||
|
||
|
||
class SocialSignalHandlerTradingModeConsumer(trading_modes.AbstractTradingModeConsumer): | ||
|
||
def __init__(self, trading_mode): | ||
super().__init__(trading_mode) | ||
trading_config = self.trading_mode.trading_config if self.trading_mode else {} | ||
|
||
self.BUY_WITH_MAXIMUM_SIZE_ORDERS = trading_config.get("buy_with_maximum_size_orders", False) | ||
self.SELL_WITH_MAXIMUM_SIZE_ORDERS = trading_config.get("sell_with_maximum_size_orders", False) | ||
|
||
async def create_new_orders(self, symbol, final_note, state, **kwargs): | ||
timeout = kwargs.pop("timeout", trading_constants.ORDER_DATA_FETCHING_TIMEOUT) | ||
try: | ||
current_symbol_holding, current_market_holding, market_quantity, price, symbol_market = \ | ||
await trading_personal_data.get_pre_order_data(self.exchange_manager, symbol=symbol, timeout=timeout) | ||
created_orders = [] | ||
|
||
market_quantity *= 0.99 | ||
if state == trading_enums.EvaluatorStates.VERY_LONG.value: | ||
for order_quantity, order_price in trading_personal_data.check_and_adapt_order_details_if_necessary( | ||
market_quantity, price, | ||
symbol_market): | ||
current_order = trading_personal_data.create_order_instance(trader=self.exchange_manager.trader, | ||
order_type=trading_enums.TraderOrderType.BUY_MARKET, | ||
symbol=symbol, | ||
current_price=order_price, | ||
quantity=order_quantity, | ||
price=order_price) | ||
await self.exchange_manager.trader.create_order(current_order) | ||
created_orders.append(current_order) | ||
return created_orders | ||
except Exception as e: | ||
self.logger.exception(e, True, f"Failed to create order : {e}.") | ||
return [] | ||
|
||
|
||
class SocialSignalHandlerTradingModeProducer(trading_modes.AbstractTradingModeProducer): | ||
TAKE_PROFITS_INCREMENTS = [1.2, 1.5, 2.0, 2.5, 3.0] | ||
|
||
def __init__(self, channel, config, trading_mode, exchange_manager): | ||
super().__init__(channel, config, trading_mode, exchange_manager) | ||
self.state = None | ||
|
||
def is_cryptocurrency_wildcard(self): | ||
return True | ||
|
||
def is_symbol_wildcard(self): | ||
return True | ||
|
||
async def set_final_eval(self, matrix_id: str, cryptocurrency: str, symbol: str, time_frame): | ||
self.state = trading_enums.EvaluatorStates.VERY_LONG | ||
self.logger.info(f"[{symbol}] new state: {self.state.name}") | ||
|
||
# call orders creation from consumers | ||
await self.submit_trading_evaluation(cryptocurrency=cryptocurrency, | ||
symbol=symbol, | ||
time_frame=None, | ||
final_note=self.final_eval, | ||
state=self.state) | ||
|
||
# send_notification | ||
if not self.exchange_manager.is_backtesting: | ||
await self._send_alert_notification(symbol, self.state) | ||
|
||
async def order_callback(self, order): | ||
# Ensure order market has not expired | ||
if order[trading_enums.ExchangeConstantsOrderColumns.STATUS.value] == trading_enums.OrderStatus.EXPIRED.value: | ||
current_order = trading_personal_data.create_order_instance( | ||
trader=self.exchange_manager.trader, | ||
order_type=trading_enums.TraderOrderType.BUY_MARKET, | ||
symbol=order[trading_enums.ExchangeConstantsOrderColumns.SYMBOL.value], | ||
current_price=decimal.Decimal(str(order[trading_enums.ExchangeConstantsOrderColumns.PRICE.value])), | ||
quantity=decimal.Decimal(str(order[trading_enums.ExchangeConstantsOrderColumns.AMOUNT.value])), | ||
price=decimal.Decimal(str(order[trading_enums.ExchangeConstantsOrderColumns.PRICE.value]))) | ||
await self.exchange_manager.trader.create_order(current_order) | ||
|
||
# When buy market order is filled | ||
if order[trading_enums.ExchangeConstantsOrderColumns.STATUS.value] == trading_enums.OrderStatus.FILLED.value: | ||
# create order on the order side | ||
symbol = order[trading_enums.ExchangeConstantsOrderColumns.SYMBOL.value] | ||
filled_price = decimal.Decimal(str(order[trading_enums.ExchangeConstantsOrderColumns.PRICE.value])) | ||
filled_volume = decimal.Decimal(str(order[trading_enums.ExchangeConstantsOrderColumns.FILLED.value])) | ||
symbol_market_status = self.exchange_manager.exchange.get_market_status(symbol, with_fixer=False) | ||
created_orders = [] | ||
for increment in self.TAKE_PROFITS_INCREMENTS: | ||
created_orders.append(await self.create_take_profit_order( | ||
filled_volume, filled_price, increment, symbol_market_status)) | ||
|
||
async def create_take_profit_order(self, filled_quantity, filled_price, increment, symbol, symbol_market_status): | ||
quantity_to_sell = filled_quantity / len(self.TAKE_PROFITS_INCREMENTS) | ||
price_to_sell = filled_price * decimal.Decimal(str(increment)) | ||
created_orders = [] | ||
for order_quantity, order_price in trading_personal_data.check_and_adapt_order_details_if_necessary( | ||
quantity_to_sell, price_to_sell, symbol_market_status): | ||
current_order = trading_personal_data.create_order_instance(trader=self.exchange_manager.trader, | ||
order_type=trading_enums.TraderOrderType.SELL_LIMIT, | ||
symbol=symbol, | ||
current_price=order_price, | ||
quantity=order_quantity, | ||
price=order_price) | ||
await self.exchange_manager.trader.create_order(current_order) | ||
created_orders.append(current_order) | ||
return created_orders | ||
|
||
@classmethod | ||
def get_should_cancel_loaded_orders(cls): | ||
return False | ||
|
||
async def _send_alert_notification(self, symbol, new_state): | ||
try: | ||
import octobot_services.api as services_api | ||
import octobot_services.enums as services_enum | ||
title = f"Social signal received on #{symbol}" | ||
alert_content, alert_content_markdown = pretty_printer.cryptocurrency_alert( | ||
new_state, | ||
self.final_eval) | ||
await services_api.send_notification(services_api.create_notification( | ||
alert_content, title=title, markdown_text=alert_content_markdown, | ||
category=services_enum.NotificationCategory.PRICE_ALERTS)) | ||
except ImportError as e: | ||
self.logger.exception(e, True, f"Impossible to send notification: {e}") | ||
|
||
|
||
class SocialSignalHandlerTradingMode(trading_modes.AbstractTradingMode): | ||
MODE_PRODUCER_CLASSES = [SocialSignalHandlerTradingModeProducer] | ||
MODE_CONSUMER_CLASSES = [SocialSignalHandlerTradingModeConsumer] | ||
|
||
def __init__(self, config, exchange_manager): | ||
super().__init__(config, exchange_manager) | ||
self.load_config() | ||
|
||
async def create_consumers(self) -> list: | ||
consumers = await super().create_consumers() | ||
|
||
# order consumer: filter by symbol not be triggered only on this symbol's orders | ||
order_consumer = await exchanges_channel.get_chan(trading_personal_data.OrdersChannel.get_name(), | ||
self.exchange_manager.id).new_consumer( | ||
self._order_notification_callback, | ||
symbol=self.symbol if self.symbol else channel_constants.CHANNEL_WILDCARD | ||
) | ||
consumers.append(order_consumer) | ||
return consumers | ||
|
||
async def _order_notification_callback(self, exchange, exchange_id, | ||
cryptocurrency, symbol, order, is_new, is_from_bot): | ||
await self.producers[0].order_callback(order) |