From 0346605a4a9cd15ef958606f22b3ce9fb63d792c Mon Sep 17 00:00:00 2001 From: Herklos Date: Fri, 30 Jan 2026 13:49:55 +0100 Subject: [PATCH 1/2] [ProfileCopyTrading] Update description and config --- .../config/ProfileCopyTradingMode.json | 2 +- .../resources/ProfileCopyTradingMode.md | 98 ++++++++++++++++++- 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/Trading/Mode/profile_copy_trading_mode/config/ProfileCopyTradingMode.json b/Trading/Mode/profile_copy_trading_mode/config/ProfileCopyTradingMode.json index 6fe16cc1d..9cd899a59 100644 --- a/Trading/Mode/profile_copy_trading_mode/config/ProfileCopyTradingMode.json +++ b/Trading/Mode/profile_copy_trading_mode/config/ProfileCopyTradingMode.json @@ -1,6 +1,6 @@ { "required_strategies": [], - "refresh_interval": 1, + "refresh_interval": 0, "rebalance_trigger_min_percent": 5, "exchange_profile_ids": [], "per_exchange_profile_portfolio_ratio": 20, diff --git a/Trading/Mode/profile_copy_trading_mode/resources/ProfileCopyTradingMode.md b/Trading/Mode/profile_copy_trading_mode/resources/ProfileCopyTradingMode.md index 00d7bdd40..a57d8d1eb 100644 --- a/Trading/Mode/profile_copy_trading_mode/resources/ProfileCopyTradingMode.md +++ b/Trading/Mode/profile_copy_trading_mode/resources/ProfileCopyTradingMode.md @@ -1 +1,97 @@ -WIP +## ProfileCopyTradingMode + +The Profile Copy Trading mode automatically copies the trading positions of one or more exchange profiles (such as Polymarket trader profiles) to your own account. It monitors the selected profiles in real-time and replicates their portfolio distribution, allowing you to mirror successful traders' strategies automatically. + +This trading mode is particularly useful for prediction markets like Polymarket, where you can follow top traders and automatically copy their positions with your own capital allocation. + +### How to Get Started + +1. **Configure your exchange**: Add and configure your exchange (e.g., Polymarket) in your OctoBot profile. Make sure your exchange credentials are properly set up. + +2. **Find exchange profile IDs**: You need to identify the profile IDs you want to copy. For Polymarket, these are typically found in the profile URL or leaderboard. For example, a Polymarket profile URL might be `https://polymarket.com/profile/0x1234...`, where `0x1234...` is the profile ID. + +3. **Configure portfolio allocation**: Set how much of your portfolio should be allocated to copying each profile. Ensure the total allocation doesn't exceed 100% of your portfolio. + +4. **Start trading**: Once configured, OctoBot will start monitoring the selected profiles and automatically adjust your portfolio to match their positions. + +### Configuration Parameters + +#### Exchange Profile IDs (`exchange_profile_ids`) + +A list of exchange profile identifiers to copy. Each profile ID should be a valid identifier on the target exchange. + +**Example**: To copy two Polymarket profiles, you would enter: +- `0x1234567890abcdef1234567890abcdef12345678` +- `0xabcdefabcdefabcdefabcdefabcdefabcdefabcd` + +You can copy multiple profiles simultaneously. The portfolio allocation will be split among all profiles according to `per_exchange_profile_portfolio_ratio`. Profile IDs are exchange-specific (e.g., Polymarket uses Ethereum addresses). + +#### Per Exchange Profile Portfolio Ratio (`per_exchange_profile_portfolio_ratio`) + +The percentage of your total portfolio value to allocate to copying each exchange profile. This value is applied to each profile in the `exchange_profile_ids` list. + +**Example**: If you have 2 profiles and set this to 30%, each profile gets 30% of your portfolio (total: 60%). If you have 1 profile and set this to 50%, that profile gets 50% of your portfolio. + +**Important**: The total allocation (number of profiles × per profile ratio) must not exceed 100%. OctoBot will validate this and prevent invalid configurations. + +**Example validation**: +- 3 profiles × 35% each = 105% → **Invalid** (exceeds 100%) +- 3 profiles × 30% each = 90% → **Valid** +- 2 profiles × 50% each = 100% → **Valid** + +#### New Position Only (`new_position_only`) + +*Not supported on Polymarket* + +When enabled, only positions opened after OctoBot started will be considered for copying. Existing positions in the tracked profiles are ignored. + +**Use cases**: +- Set to `true` to only copy new trades made by the profile after you start following them +- Set to `false` to copy the entire current portfolio of the profile, including positions they opened before you started following + +#### Unrealized PnL Percent (`min_unrealized_pnl_percent` and `max_unrealized_pnl_percent`) + +Filter positions based on their unrealized profit/loss ratio relative to their collateral. Values are expressed as decimal ratios (0.1 = 10%). + +**Minimum Unrealized PnL Percent** (`min_unrealized_pnl_percent`): Only copy positions that have at least this unrealized profit/loss ratio. For example, set to `0.05` to filter out losing positions and only copy positions with at least 5% unrealized profit, or set to `0.1` to copy only positions with at least 10% unrealized profit. + +**Maximum Unrealized PnL Percent** (`max_unrealized_pnl_percent`): Only copy positions that have at most this unrealized profit/loss ratio. For example, set to `0.5` to avoid copying positions with more than 50% unrealized profit (might be too risky), or set to `0.2` to cap at 20% unrealized profit and limit exposure to highly profitable positions. + +Set either parameter to `None` to disable that filter. + +#### Mark Price (`min_mark_price` and `max_mark_price`) + +Filter positions based on their mark price (current market price). Useful for filtering positions by price range. + +**Minimum Mark Price** (`min_mark_price`): Only copy positions with a mark price greater than or equal to this value. For example, set to `0.5` to focus on higher-value markets and only copy positions in markets priced at $0.50 or higher, or set to `0.1` to filter out very cheap positions. + +**Maximum Mark Price** (`max_mark_price`): Only copy positions with a mark price less than or equal to this value. For example, set to `0.8` to focus on lower-value markets and only copy positions in markets priced at $0.80 or lower, or set to `0.9` to filter out positions near certainty. + +Set either parameter to `None` to disable that filter. + +### Portfolio Allocation Validation + +OctoBot automatically validates that your portfolio allocation is feasible: +- Total allocation = `per_exchange_profile_portfolio_ratio` × number of profiles +- This total must be ≤ 100% +- If validation fails, OctoBot will raise an error and prevent starting the trading mode + +**Example validation**: +- 3 profiles × 35% each = 105% → **Invalid** (exceeds 100%) +- 3 profiles × 30% each = 90% → **Valid** +- 2 profiles × 50% each = 100% → **Valid** + +### Troubleshooting + +**Issue**: "Distribution for all exchange profiles are not yet available" +- **Solution**: Wait for the Exchange Service Feed to provide data from all configured profiles. This is normal on startup. + +**Issue**: "Total portfolio allocation exceeds 100%" +- **Solution**: Reduce `per_exchange_profile_portfolio_ratio` or reduce the number of profiles in `exchange_profile_ids`. + +**Issue**: "Impossible to find the Exchange service feed" +- **Solution**: Ensure the Exchange Service Feed tentacle is installed and enabled in your OctoBot configuration. + +**Note**: Since Profile Copy Trading mode extends the Index Trading Mode, it also supports Index Trading Mode parameters such as `refresh_interval` and `rebalance_trigger_min_percent` for controlling portfolio rebalancing behavior. + +_This trading mode supports backtesting and is compatible with PNL history._ From 5e6603a20426e7ea1a6112f38c9d7fc41c1b9702 Mon Sep 17 00:00:00 2001 From: Herklos Date: Fri, 30 Jan 2026 14:07:05 +0100 Subject: [PATCH 2/2] [Polymarket] Fix min orders limits --- .../polymarket/ccxt/polymarket_async.py | 28 ++++++++++++- .../polymarket/ccxt/polymarket_sync.py | 28 ++++++++++++- .../resources/ProfileCopyTradingMode.md | 41 ++++++++++++------- 3 files changed, 79 insertions(+), 18 deletions(-) diff --git a/Trading/Exchange/polymarket/ccxt/polymarket_async.py b/Trading/Exchange/polymarket/ccxt/polymarket_async.py index d10a31500..05301df50 100644 --- a/Trading/Exchange/polymarket/ccxt/polymarket_async.py +++ b/Trading/Exchange/polymarket/ccxt/polymarket_async.py @@ -423,6 +423,20 @@ def describe(self) -> Any: }, }, }, + 'limits': { + 'amount': { + 'min': 5, # Minimum order size + 'max': None, + }, + 'price': { + 'min': 1e-6, # Prediction markets are >0 and <1 + 'max': 1, # Prediction markets are 0-1 + }, + 'cost': { + 'min': None, + 'max': None, + }, + }, 'exceptions': { 'exact': { # HTTP status codes @@ -789,11 +803,11 @@ def parse_market(self, market: dict) -> Market: 'max': None, }, 'amount': { - 'min': None, + 'min': 5, # Minimum order size 'max': None, }, 'price': { - 'min': 0, # Prediction markets are 0-1 + 'min': 1e-6, # Prediction markets are >0 and <1 'max': 1, # Prediction markets are 0-1 }, 'cost': { @@ -979,10 +993,20 @@ def parse_order_book(self, orderbook: dict, symbol: Str = None, timestamp: Int = metadata: dict = {} if tickSize is not None: metadata['tick_size'] = tickSize + # Update market precision with tick_size if available + if self.markets is not None and symbol in self.markets: + market = self.markets[symbol] + if market['precision']['price'] is None or market['precision']['price'] == 6: + market['precision']['price'] = self.parse_number(tickSize) if negRisk is not None: metadata['neg_risk'] = negRisk if minOrderSize is not None: metadata['min_order_size'] = minOrderSize + # Update market limits with min_order_size if available + if self.markets is not None and symbol in self.markets: + market = self.markets[symbol] + if market['limits']['amount']['min'] is None: + market['limits']['amount']['min'] = self.parse_number(minOrderSize) result['info'] = self.extend(orderbook, metadata) return result diff --git a/Trading/Exchange/polymarket/ccxt/polymarket_sync.py b/Trading/Exchange/polymarket/ccxt/polymarket_sync.py index 6818dc543..bf3bbe7f1 100644 --- a/Trading/Exchange/polymarket/ccxt/polymarket_sync.py +++ b/Trading/Exchange/polymarket/ccxt/polymarket_sync.py @@ -423,6 +423,20 @@ def describe(self) -> Any: }, }, }, + 'limits': { + 'amount': { + 'min': 5, # Minimum order size + 'max': None, + }, + 'price': { + 'min': 1e-6, # Prediction markets are >0 and <1 + 'max': 1, # Prediction markets are 0-1 + }, + 'cost': { + 'min': None, + 'max': None, + }, + }, 'exceptions': { 'exact': { # HTTP status codes @@ -789,11 +803,11 @@ def parse_market(self, market: dict) -> Market: 'max': None, }, 'amount': { - 'min': None, + 'min': 5, # Minimum order size 'max': None, }, 'price': { - 'min': 0, # Prediction markets are 0-1 + 'min': 1e-6, # Prediction markets are >0 and <1 'max': 1, # Prediction markets are 0-1 }, 'cost': { @@ -979,10 +993,20 @@ def parse_order_book(self, orderbook: dict, symbol: Str = None, timestamp: Int = metadata: dict = {} if tickSize is not None: metadata['tick_size'] = tickSize + # Update market precision with tick_size if available + if self.markets is not None and symbol in self.markets: + market = self.markets[symbol] + if market['precision']['price'] is None or market['precision']['price'] == 6: + market['precision']['price'] = self.parse_number(tickSize) if negRisk is not None: metadata['neg_risk'] = negRisk if minOrderSize is not None: metadata['min_order_size'] = minOrderSize + # Update market limits with min_order_size if available + if self.markets is not None and symbol in self.markets: + market = self.markets[symbol] + if market['limits']['amount']['min'] is None: + market['limits']['amount']['min'] = self.parse_number(minOrderSize) result['info'] = self.extend(orderbook, metadata) return result diff --git a/Trading/Mode/profile_copy_trading_mode/resources/ProfileCopyTradingMode.md b/Trading/Mode/profile_copy_trading_mode/resources/ProfileCopyTradingMode.md index a57d8d1eb..24cb19c08 100644 --- a/Trading/Mode/profile_copy_trading_mode/resources/ProfileCopyTradingMode.md +++ b/Trading/Mode/profile_copy_trading_mode/resources/ProfileCopyTradingMode.md @@ -16,7 +16,7 @@ This trading mode is particularly useful for prediction markets like Polymarket, ### Configuration Parameters -#### Exchange Profile IDs (`exchange_profile_ids`) +#### Exchange Profile IDs A list of exchange profile identifiers to copy. Each profile ID should be a valid identifier on the target exchange. @@ -24,11 +24,11 @@ A list of exchange profile identifiers to copy. Each profile ID should be a vali - `0x1234567890abcdef1234567890abcdef12345678` - `0xabcdefabcdefabcdefabcdefabcdefabcdefabcd` -You can copy multiple profiles simultaneously. The portfolio allocation will be split among all profiles according to `per_exchange_profile_portfolio_ratio`. Profile IDs are exchange-specific (e.g., Polymarket uses Ethereum addresses). +You can copy multiple profiles simultaneously. The portfolio allocation will be split among all profiles according to *Per Exchange Profile Portfolio Ratio*. Profile IDs are exchange-specific (e.g., Polymarket uses Ethereum addresses). -#### Per Exchange Profile Portfolio Ratio (`per_exchange_profile_portfolio_ratio`) +#### Per Exchange Profile Portfolio Ratio -The percentage of your total portfolio value to allocate to copying each exchange profile. This value is applied to each profile in the `exchange_profile_ids` list. +The percentage of your total portfolio value to allocate to copying each exchange profile. This value is applied to each profile in the *Exchange Profile IDs* list. **Example**: If you have 2 profiles and set this to 30%, each profile gets 30% of your portfolio (total: 60%). If you have 1 profile and set this to 50%, that profile gets 50% of your portfolio. @@ -39,7 +39,20 @@ The percentage of your total portfolio value to allocate to copying each exchang - 3 profiles × 30% each = 90% → **Valid** - 2 profiles × 50% each = 100% → **Valid** -#### New Position Only (`new_position_only`) +#### Allocation Padding Ratio + +The percentage padding to allow on top of the configured portfolio allocation per profile. This allows the trading mode to use more of your portfolio than initially configured when the copied profile opens additional positions. + +**Example**: If you set *Per Exchange Profile Portfolio Ratio* to 50% and *Allocation Padding Ratio* to 20%, the effective maximum allocation for that profile can grow up to 60% (50% × 1.2). This is useful when the copied profile increases its number of traded positions over time. + +**Use cases**: +- Set to `0%` for strict allocation limits (recommended for conservative strategies) +- Set to `20-50%` to allow flexibility when the copied profile expands its portfolio +- Higher values provide more flexibility but increase risk of over-allocation + +**Important**: The padding only allows expansion beyond the configured ratio. + +#### New Position Only *Not supported on Polymarket* @@ -49,30 +62,30 @@ When enabled, only positions opened after OctoBot started will be considered for - Set to `true` to only copy new trades made by the profile after you start following them - Set to `false` to copy the entire current portfolio of the profile, including positions they opened before you started following -#### Unrealized PnL Percent (`min_unrealized_pnl_percent` and `max_unrealized_pnl_percent`) +#### Unrealized PnL Percent Filter positions based on their unrealized profit/loss ratio relative to their collateral. Values are expressed as decimal ratios (0.1 = 10%). -**Minimum Unrealized PnL Percent** (`min_unrealized_pnl_percent`): Only copy positions that have at least this unrealized profit/loss ratio. For example, set to `0.05` to filter out losing positions and only copy positions with at least 5% unrealized profit, or set to `0.1` to copy only positions with at least 10% unrealized profit. +**Minimum Unrealized PnL Percent**: Only copy positions that have at least this unrealized profit/loss ratio. For example, set to `0.05` to filter out losing positions and only copy positions with at least 5% unrealized profit, or set to `0.1` to copy only positions with at least 10% unrealized profit. -**Maximum Unrealized PnL Percent** (`max_unrealized_pnl_percent`): Only copy positions that have at most this unrealized profit/loss ratio. For example, set to `0.5` to avoid copying positions with more than 50% unrealized profit (might be too risky), or set to `0.2` to cap at 20% unrealized profit and limit exposure to highly profitable positions. +**Maximum Unrealized PnL Percent**: Only copy positions that have at most this unrealized profit/loss ratio. For example, set to `0.5` to avoid copying positions with more than 50% unrealized profit (might be too risky), or set to `0.2` to cap at 20% unrealized profit and limit exposure to highly profitable positions. Set either parameter to `None` to disable that filter. -#### Mark Price (`min_mark_price` and `max_mark_price`) +#### Mark Price Filter positions based on their mark price (current market price). Useful for filtering positions by price range. -**Minimum Mark Price** (`min_mark_price`): Only copy positions with a mark price greater than or equal to this value. For example, set to `0.5` to focus on higher-value markets and only copy positions in markets priced at $0.50 or higher, or set to `0.1` to filter out very cheap positions. +**Minimum Mark Price**: Only copy positions with a mark price greater than or equal to this value. For example, set to `0.5` to focus on higher-value markets and only copy positions in markets priced at $0.50 or higher, or set to `0.1` to filter out very cheap positions. -**Maximum Mark Price** (`max_mark_price`): Only copy positions with a mark price less than or equal to this value. For example, set to `0.8` to focus on lower-value markets and only copy positions in markets priced at $0.80 or lower, or set to `0.9` to filter out positions near certainty. +**Maximum Mark Price**: Only copy positions with a mark price less than or equal to this value. For example, set to `0.8` to focus on lower-value markets and only copy positions in markets priced at $0.80 or lower, or set to `0.9` to filter out positions near certainty. Set either parameter to `None` to disable that filter. ### Portfolio Allocation Validation OctoBot automatically validates that your portfolio allocation is feasible: -- Total allocation = `per_exchange_profile_portfolio_ratio` × number of profiles +- Total allocation = *Per Exchange Profile Portfolio Ratio* × number of profiles - This total must be ≤ 100% - If validation fails, OctoBot will raise an error and prevent starting the trading mode @@ -87,11 +100,11 @@ OctoBot automatically validates that your portfolio allocation is feasible: - **Solution**: Wait for the Exchange Service Feed to provide data from all configured profiles. This is normal on startup. **Issue**: "Total portfolio allocation exceeds 100%" -- **Solution**: Reduce `per_exchange_profile_portfolio_ratio` or reduce the number of profiles in `exchange_profile_ids`. +- **Solution**: Reduce *Per Exchange Profile Portfolio Ratio* or reduce the number of profiles in *Exchange Profile IDs*. **Issue**: "Impossible to find the Exchange service feed" - **Solution**: Ensure the Exchange Service Feed tentacle is installed and enabled in your OctoBot configuration. -**Note**: Since Profile Copy Trading mode extends the Index Trading Mode, it also supports Index Trading Mode parameters such as `refresh_interval` and `rebalance_trigger_min_percent` for controlling portfolio rebalancing behavior. +**Note**: Since Profile Copy Trading mode extends the Index Trading Mode, it also supports Index Trading Mode parameters such as *Refresh interval* and *Rebalance cap* for controlling portfolio rebalancing behavior. _This trading mode supports backtesting and is compatible with PNL history._