mirror of
https://github.com/Ichinga-Samuel/aiomql.git
synced 2026-08-09 10:17:46 +00:00
v4.0.5
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
- [calc_profit](#order.calc_profit)
|
||||
- [calc_loss](#order.calc_loss)
|
||||
- [request](#order.request)
|
||||
- [modify](#order.modify)
|
||||
|
||||
<a id="order.order"></a>
|
||||
### Order
|
||||
@@ -160,3 +161,11 @@ Return the trade request object as a dict
|
||||
| Type | Description |
|
||||
|--------|----------------------------------|
|
||||
| `dict` | Returns the trade request object |
|
||||
|
||||
|
||||
<a id="order.modify"></a>
|
||||
### modify
|
||||
```python
|
||||
def modify(**kwargs)
|
||||
```
|
||||
Modify the order object with keyword arguments.
|
||||
|
||||
+30
-7
@@ -10,6 +10,7 @@
|
||||
- [close_position_by_ticket](#positions.close_position_by_ticket)
|
||||
- [close_position](#positions.close_position)
|
||||
- [close_all](#positions.close_all)
|
||||
- [get_total_positions](#positions.get_total_positions)
|
||||
|
||||
<a id="positions.positions"></a>
|
||||
### Positions
|
||||
@@ -19,10 +20,11 @@ class Positions
|
||||
Get and handle Open positions.
|
||||
|
||||
#### Attributes
|
||||
| Name | Type | Description |
|
||||
|-------------|-----------------------------|----------------------------|
|
||||
| `positions` | `tuple[TradePosition, ...]` | Financial instrument name. |
|
||||
| `mt5` | `MetaTrader` | MetaTrader instance. |
|
||||
| Name | Type | Description |
|
||||
|-------------|-----------------------------|-------------------------------------------------------------------------------------|
|
||||
| `positions` | `tuple[TradePosition, ...]` | Financial instrument name. |
|
||||
| `mt5` | `MetaTrader` | MetaTrader instance. |
|
||||
|`total_positions`| `int` | Total number of open positions. Can be set in `get_positions` or `get_total_positions`. |
|
||||
|
||||
<a id="positions.__init__"></a>
|
||||
### \_\_init\_\_
|
||||
@@ -35,11 +37,19 @@ Initialize a position instance
|
||||
<a id="positions.get_position"></a>
|
||||
### get_positions
|
||||
```python
|
||||
async def get_positions(self) -> tuple[TradePosition, ...]:
|
||||
async def get_positions(*, symbol: str = None, ticket: int = None, group: str = None) -> tuple[TradePosition, ...]:
|
||||
```
|
||||
Get open positions
|
||||
Get open positions, with the ability to filter by symbol, ticket, or group.
|
||||
|
||||
#### Returns
|
||||
#### Parameters:
|
||||
| Name | Type | Description |
|
||||
|----------|-------|-----------------|
|
||||
| `symbol` | `str` | Symbol |
|
||||
| `ticket` | `int` | Position ticket |
|
||||
| `group` | `str` | Group name |
|
||||
|
||||
|
||||
#### Returns:
|
||||
| Type | Description |
|
||||
|-----------------------------|--------------------------------|
|
||||
| `tuple[TradePosition, ...]` | A list of open trade positions |
|
||||
@@ -150,3 +160,16 @@ Close all open positions for the trading account.
|
||||
| Type | Description |
|
||||
|-------|--------------------------------------|
|
||||
| `int` | Return total number of closed trades |
|
||||
|
||||
|
||||
<a id="positions.get_total_positions"></a>
|
||||
### get_total_positions
|
||||
```python
|
||||
async def get_total_positions() -> int
|
||||
```
|
||||
Get the total number of open positions and set the `total_positions` attribute.
|
||||
|
||||
#### Returns:
|
||||
| Type | Description |
|
||||
|-------|--------------------------------------|
|
||||
| `int` | Return total number of open trades |
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
- [get_amount](#ram.get_amount)
|
||||
- [check_losing_positions](#ram.check_losing_positions)
|
||||
- [check_open_positions](#ram.check_open_positions)
|
||||
- [modify_ram](#ram.modify_ram)
|
||||
|
||||
<a id="ram.ram"></a>
|
||||
### RAM
|
||||
@@ -75,3 +76,11 @@ Check if the number of open positions is less than or equal the loss limit.
|
||||
| Type | Description |
|
||||
|--------|---------------------------------------------------------------------------------------|
|
||||
| `bool` | True if the number of open losing trades is more than the loss limit, False otherwise |
|
||||
|
||||
|
||||
<a id="ram.modify_ram"></a>
|
||||
### modify_ram
|
||||
```python
|
||||
def modify_ram(**kwargs):
|
||||
```
|
||||
Modify the RAM attributes. All provided keyword arguments are set as attributes.
|
||||
|
||||
+12
-2
@@ -1,7 +1,8 @@
|
||||
import logging
|
||||
import asyncio
|
||||
|
||||
from aiomql.lib.bot import Bot
|
||||
from aiomql.contrib.strategies import FingerTrap
|
||||
from aiomql.contrib.strategies import FingerTrap, Chaos
|
||||
from aiomql.contrib.symbols import ForexSymbol
|
||||
|
||||
|
||||
@@ -9,10 +10,19 @@ def sample_bot():
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
syms = ["Volatility 75 Index", "Volatility 100 Index", "Volatility 50 Index"]
|
||||
symbols = [ForexSymbol(name=sym) for sym in syms]
|
||||
strategies = [FingerTrap(symbol=symbol) for symbol in symbols]
|
||||
strategies = [Chaos(symbol=symbol) for symbol in symbols]
|
||||
bot = Bot()
|
||||
bot.add_coroutine(coroutine=pray_sleep)
|
||||
bot.add_strategies(strategies=strategies)
|
||||
bot.timeout = 10
|
||||
bot.execute()
|
||||
|
||||
|
||||
async def pray_sleep():
|
||||
while True:
|
||||
print("I'm praying")
|
||||
await asyncio.sleep(10)
|
||||
print("I'm done praying")
|
||||
|
||||
|
||||
sample_bot()
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
hcc,symbol,expected_profit,win,date,closed,ask,bid,lcc,deal,order,price,htf,slow_ema,name,actual_profit,volume,ltf,fast_ema
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:07:29.043539,False,78828.04,78806.16,100,8085845438,8177248286,78806.16,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:07:29.044543,False,1314.12,1313.68,100,8085845455,8177248293,1314.12,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:07:31.025102,False,324.4566,324.4146,100,8085845467,8177248312,324.4566,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:17:11.021084,False,78735.37,78713.49,100,8085851022,8177253835,78735.37,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:17:13.020086,False,1314.32,1313.88,100,8085851041,8177253853,1313.88,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:17:15.008086,False,324.0193,323.9773,100,8085851069,8177253868,323.9773,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:18:53.017326,False,78704.04,78682.16,100,8085852163,8177254989,78704.04,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:18:55.011474,False,1316.37,1315.93,100,8085852178,8177254993,1315.93,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:18:55.013474,False,324.2283,324.1863,100,8085852215,8177255002,324.2283,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:23:27.010827,False,78778.03,78756.15,100,8085854936,8177257787,78756.15,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:23:29.006832,False,1314.3,1313.86,100,8085854954,8177257793,1313.86,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:23:31.003828,False,323.2684,323.2264,100,8085854975,8177257823,323.2264,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:26:09.025801,False,323.7008,323.6588,100,8085856583,8177259466,323.7008,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:26:11.005802,False,78884.84,78862.96,100,8085856572,8177259463,78884.84,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:26:11.006799,False,1310.66,1310.22,100,8085856599,8177259477,1310.22,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:28:03.006334,False,78939.57,78917.69,100,8085857526,8177260436,78917.69,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:28:03.009335,False,324.7318,324.6898,100,8085857558,8177260446,324.7318,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:28:05.005331,False,1310.94,1310.5,100,8085857566,8177260475,1310.5,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:29:27.015041,False,1315.82,1315.38,100,8085858344,8177261262,1315.82,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:29:28.999563,False,324.8365,324.7945,100,8085858386,8177261317,324.8365,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:29:31.012566,False,78947.5,78925.62,100,8085858423,8177261341,78925.62,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:30:01.032756,False,79079.21,79057.33,100,8085858955,8177261893,79079.21,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:30:05.024759,False,324.6382,324.5962,100,8085859011,8177261936,324.5962,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:30:05.024759,False,1314.79,1314.35,100,8085858996,8177261910,1314.79,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:31:33.026074,False,79188.35,79166.47,100,8085859867,8177262831,79188.35,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:31:35.021076,False,324.5792,324.5372,100,8085859885,8177262838,324.5792,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:31:37.016075,False,1315.72,1315.28,100,8085859896,8177262856,1315.72,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:32:03.020861,False,324.5508,324.5088,100,8085860182,8177263172,324.5088,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:32:03.020861,False,79179.99,79158.11,100,8085860212,8177263178,79179.99,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:32:05.021850,False,1316.68,1316.24,100,8085860224,8177263198,1316.68,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:40:05.004954,False,78914.24,78892.36,100,8085864656,8177267909,78914.24,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:40:09.002958,False,1319.72,1319.28,100,8085864692,8177267937,1319.72,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:40:09.002958,False,324.1071,324.0651,100,8085864666,8177267919,324.0651,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:43:33.009120,False,1320.3,1319.86,100,8085866996,8177270427,1319.86,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:43:34.999654,False,78827.52,78805.64,100,8085867046,8177270431,78805.64,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:43:37.008651,False,324.4128,324.3708,100,8085867079,8177270484,324.4128,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:48:24.003478,False,78766.18,78744.3,100,8085870210,8177274131,78744.3,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:48:25.018483,False,1315.64,1315.2,100,8085870233,8177274174,1315.2,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:48:27.009492,False,324.5763,324.5343,100,8085870256,8177274178,324.5763,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:50:01.007484,False,323.9372,323.8952,100,8085871271,8177275350,323.9372,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:50:03.060484,False,1317.61,1317.17,100,8085871292,8177275364,1317.17,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:50:05.028515,False,78781.57,78759.69,100,8085871329,8177275399,78781.57,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 19:59:45.021172,False,1321.83,1321.39,100,8085877825,8177282928,1321.83,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 19:59:45.021172,False,79163.75,79141.87,100,8085877857,8177282969,79141.87,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 19:59:47.000175,False,323.1256,323.0836,100,8085877884,8177283006,323.1256,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:00:00.990594,False,79155.16,79133.28,100,8085878145,8177283326,79133.28,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:00:05.003599,False,323.1065,323.0645,100,8085878237,8177283399,323.0645,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:00:05.002594,False,1321.13,1320.69,100,8085878211,8177283349,1321.13,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:07:15.071021,False,79195.7,79173.82,100,8085882944,8177288643,79173.82,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:07:15.071021,False,1327.97,1327.53,100,8085882911,8177288633,1327.53,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:07:16.994022,False,323.3865,323.3445,100,8085882970,8177288685,323.3865,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:11:13.010367,False,79335.81,79313.93,100,8085885622,8177291571,79313.93,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:11:13.011365,False,1331.92,1331.48,100,8085885650,8177291589,1331.48,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:11:15.003365,False,323.7561,323.7141,100,8085885678,8177291620,323.7561,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:20:45.002184,False,79546.91,79525.03,100,8085892281,8177298716,79546.91,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:20:47.006180,False,324.5659,324.5239,100,8085892320,8177298720,324.5239,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:26:03.185662,False,1327.57,1327.13,100,8085895725,8177302365,1327.13,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:26:09.067255,False,79305.74,79283.86,100,8085895753,8177302415,79305.74,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:26:10.995026,False,324.5796,324.5376,100,8085895762,8177302423,324.5796,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:27:24.995204,False,79276.47,79254.59,100,8085896466,8177303186,79254.59,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:27:24.996204,False,324.3086,324.2666,100,8085896491,8177303215,324.2666,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:27:27.202795,False,1325.12,1324.68,100,8085896500,8177303231,1325.12,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:28:27.002144,False,1327.2,1326.76,100,8085897009,8177303797,1326.76,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:28:27.005145,False,79278.85,79256.97,100,8085897062,8177303803,79278.85,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:28:28.984144,False,323.8883,323.8463,100,8085897065,8177303851,323.8463,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:30:37.011482,False,323.6916,323.6496,100,8085898139,8177305049,323.6916,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:30:37.013482,False,79355.87,79333.99,100,8085898161,8177305066,79333.99,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:30:38.987481,False,1323.99,1323.55,100,8085898234,8177305138,1323.55,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:32:02.983816,False,79441.61,79419.73,100,8085899199,8177306191,79419.73,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:32:02.983816,False,324.0681,324.0261,100,8085899220,8177306207,324.0681,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:32:06.983816,False,1323.5,1323.06,100,8085899268,8177306245,1323.06,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:34:23.020570,False,79326.19,79304.31,100,8085900581,8177307689,79326.19,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:34:23.021571,False,1322.72,1322.28,100,8085900539,8177307655,1322.28,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:34:25.418569,False,324.5077,324.4657,100,8085900595,8177307723,324.4657,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:36:27.244005,False,79153.28,79131.4,100,8085901660,8177308881,79153.28,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:36:29.162006,False,1327.12,1326.68,100,8085901692,8177308905,1326.68,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:36:31.090003,False,324.2543,324.2123,100,8085901712,8177308927,324.2543,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:37:55.001817,False,1330.68,1330.24,100,8085902742,8177310025,1330.24,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:37:55.005820,False,324.3003,324.2583,100,8085902726,8177310019,324.3003,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:37:57.137818,False,79212.21,79190.33,100,8085902754,8177310052,79212.21,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:38:00.997822,False,79235.35,79213.47,100,8085902806,8177310123,79213.47,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:38:02.991111,False,1330.38,1329.94,100,8085902841,8177310137,1329.94,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:38:05.006113,False,324.2726,324.2306,100,8085902911,8177310210,324.2306,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:38:55.053360,False,79305.75,79283.87,100,8085903412,8177310761,79283.87,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:38:55.053360,False,324.3933,324.3513,100,8085903371,8177310737,324.3513,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:38:57.001887,False,1331.91,1331.47,100,8085903430,8177310799,1331.47,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:40:03.262107,False,79163.49,79141.61,100,8085904300,8177311720,79163.49,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:40:03.264107,False,324.0259,323.9839,100,8085904337,8177311725,323.9839,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:40:05.003108,False,1330.35,1329.91,100,8085904359,8177311739,1330.35,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:40:46.988140,False,79151.03,79129.15,100,8085904778,8177312217,79151.03,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:40:48.985138,False,324.3079,324.2659,100,8085904790,8177312229,324.2659,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:40:50.986140,False,1330.57,1330.13,100,8085904803,8177312244,1330.13,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:42:01.031448,False,324.4332,324.3912,100,8085905489,8177313005,324.3912,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:42:02.998450,False,1330.59,1330.15,100,8085905509,8177313007,1330.15,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:42:04.974450,False,79049.18,79027.3,100,8085905524,8177313022,79049.18,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:44:49.011685,False,79043.68,79021.8,100,8085907248,8177314937,79043.68,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:44:49.018687,False,1327.85,1327.41,100,8085907276,8177314945,1327.85,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:44:50.994684,False,324.38,324.338,100,8085907281,8177314958,324.38,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:46:10.984008,False,79014.9,78993.02,100,8085908427,8177316197,79014.9,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:46:10.988010,False,1325.75,1325.31,100,8085908465,8177316206,1325.75,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:46:12.986011,False,324.4139,324.3719,100,8085908501,8177316232,324.3719,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:47:22.986968,False,1327.04,1326.6,100,8085909571,8177317543,1326.6,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:47:25.026967,False,78945.11,78923.23,100,8085909774,8177317561,78923.23,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:47:26.985965,False,324.397,324.355,100,8085909787,8177317592,324.355,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:48:02.999449,False,1324.0,1323.56,100,8085910188,8177318015,1323.56,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:48:04.993447,False,78947.31,78925.43,100,8085910198,8177318021,78947.31,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:48:07.015973,False,324.4016,324.3596,100,8085910207,8177318037,324.4016,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 20:56:02.985263,False,1316.4,1315.96,100,8085915185,8177323496,1316.4,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 20:56:07.096263,False,78879.35,78857.47,100,8085915321,8177323587,78879.35,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 20:56:07.097263,False,325.0526,325.0106,100,8085915213,8177323504,325.0106,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:00:26.983944,False,78862.56,78840.68,100,8085918435,8177327000,78862.56,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:00:26.984945,False,1313.12,1312.68,100,8085918457,8177327025,1312.68,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:00:30.984611,False,325.5656,325.5236,100,8085918494,8177327056,325.5656,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:02:00.977445,False,1311.5,1311.06,100,8085919286,8177327975,1311.5,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:02:04.990740,False,325.6578,325.6158,100,8085919367,8177328006,325.6578,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:02:04.991741,False,78846.58,78824.7,100,8085919309,8177327988,78824.7,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:03:45.003292,False,78840.3,78818.42,100,8085920342,8177329082,78818.42,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:03:46.993293,False,1313.65,1313.21,100,8085920366,8177329117,1313.65,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:03:48.986293,False,325.4783,325.4363,100,8085920381,8177329134,325.4363,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:04:00.984264,False,325.4041,325.3621,100,8085920473,8177329247,325.3621,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:04:03.007493,False,78868.29,78846.41,100,8085920496,8177329261,78846.41,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:04:04.977495,False,1312.89,1312.45,100,8085920516,8177329279,1312.45,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:06:02.973242,False,325.5582,325.5162,100,8085921686,8177330570,325.5582,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:06:02.974244,False,78756.09,78734.21,100,8085921702,8177330577,78756.09,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:06:05.004242,False,1312.65,1312.21,100,8085921716,8177330589,1312.65,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:07:20.984882,False,78874.77,78852.89,100,8085922565,8177331499,78852.89,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:07:20.986878,False,1312.95,1312.51,100,8085922587,8177331522,1312.51,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:07:22.988876,False,325.8438,325.8018,100,8085922602,8177331544,325.8438,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:08:44.970353,False,1312.78,1312.34,100,8085923629,8177332630,1312.78,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:08:44.971353,False,78969.9,78948.02,100,8085923623,8177332606,78969.9,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:08:46.973352,False,325.8749,325.8329,100,8085923655,8177332646,325.8329,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:10:06.974890,False,326.2115,326.1695,100,8085924362,8177333420,326.2115,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:10:06.973888,False,78988.92,78967.04,100,8085924384,8177333426,78967.04,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:10:06.974890,False,1311.71,1311.27,100,8085924404,8177333462,1311.27,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:12:03.085605,False,326.2136,326.1716,100,8085925439,8177334592,326.1716,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:12:04.971308,False,79113.59,79091.71,100,8085925422,8177334585,79113.59,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:12:07.002310,False,1311.24,1310.8,100,8085925464,8177334616,1311.24,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:13:52.980316,False,79117.98,79096.1,100,8085926462,8177335712,79096.1,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:33:52.228712,False,1311.99,1311.55,100,8085937713,8177348003,1311.99,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:33:52.229715,False,79027.4,79005.52,100,8085937719,8177348008,79027.4,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:33:54.259839,False,325.8998,325.8578,100,8085937731,8177348021,325.8578,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:34:04.565096,False,1310.56,1310.12,100,8085937810,8177348106,1310.56,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:34:04.565096,False,325.9881,325.9461,100,8085937790,8177348082,325.9461,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:34:06.221092,False,79026.49,79004.61,100,8085937814,8177348126,79026.49,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:36:02.252949,False,78804.93,78783.05,100,8085939146,8177349529,78804.93,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:36:04.244949,False,326.2347,326.1927,100,8085939198,8177349581,326.1927,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:36:06.223949,False,1308.0,1307.56,100,8085939217,8177349600,1307.56,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 75 Index,0,False,2024-11-30 21:38:02.266525,False,78772.16,78750.28,100,8085940552,8177351016,78750.28,TIMEFRAME_M2,20,Chaos,0,0.001,TIMEFRAME_M1,8
|
||||
100,Volatility 100 Index,0,False,2024-11-30 21:38:06.239554,False,1310.95,1310.51,100,8085940602,8177351089,1310.95,TIMEFRAME_M2,20,Chaos,0,0.5,TIMEFRAME_M1,8
|
||||
100,Volatility 50 Index,0,False,2024-11-30 21:38:06.239554,False,325.7652,325.7232,100,8085940571,8177351044,325.7652,TIMEFRAME_M2,20,Chaos,0,4.0,TIMEFRAME_M1,8
|
||||
|
+74
-5
@@ -10,7 +10,35 @@ from .core.config import Config
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
config = Config()
|
||||
|
||||
async def backtest_sleep(secs: float):
|
||||
config = Config()
|
||||
btc = config.backtest_controller
|
||||
try:
|
||||
if btc.parties == 2:
|
||||
steps = int(secs) // config.backtest_engine.speed
|
||||
steps = max(steps, 1)
|
||||
config.backtest_engine.fast_forward(steps=steps)
|
||||
btc.wait()
|
||||
|
||||
elif btc.parties > 2:
|
||||
_time = config.backtest_engine.cursor.time + secs
|
||||
while _time > config.backtest_engine.cursor.time:
|
||||
btc.wait()
|
||||
else:
|
||||
btc.wait()
|
||||
except Exception as err:
|
||||
btc.wait()
|
||||
logger.error("Error: %s in backtest_sleep", err)
|
||||
|
||||
|
||||
# async def backtest_sleep(secs):
|
||||
# """An async sleep function for use during backtesting."""
|
||||
# btc = BackTestController()
|
||||
# config = Config()
|
||||
# sleep = config.backtest_engine.cursor.time + secs
|
||||
# while sleep > config.backtest_engine.cursor.time:
|
||||
# btc.wait()
|
||||
|
||||
|
||||
def dict_to_string(data: dict, multi=False) -> str:
|
||||
@@ -28,6 +56,13 @@ def dict_to_string(data: dict, multi=False) -> str:
|
||||
|
||||
|
||||
def backoff_decorator(func=None, *, max_retries: int = 2, retries: int = 0, error="") -> callable:
|
||||
"""A decorator to retry a function a number of times before giving up.
|
||||
Args:
|
||||
func (callable, optional): The function to decorate. Defaults to None.
|
||||
max_retries (int, optional): The maximum number of retries. Defaults to 2.
|
||||
retries (int, optional): The number of retries. Defaults to 0.
|
||||
error (Any, optional): The error to raise when the maximum number of retries is reached. Defaults to "".
|
||||
"""
|
||||
if func is None:
|
||||
return partial(backoff_decorator, max_retries=max_retries, retries=retries, error=error)
|
||||
|
||||
@@ -47,7 +82,7 @@ def backoff_decorator(func=None, *, max_retries: int = 2, retries: int = 0, erro
|
||||
return res
|
||||
except Exception as err:
|
||||
logger.error("Error in %s: %s", func.__name__, err)
|
||||
if config.mode != "backtest":
|
||||
if Config().mode != "backtest":
|
||||
await asyncio.sleep(2**retries + random.uniform(0, max_retries))
|
||||
await wrapper(*args, **kwargs)
|
||||
|
||||
@@ -55,6 +90,14 @@ def backoff_decorator(func=None, *, max_retries: int = 2, retries: int = 0, erro
|
||||
|
||||
|
||||
def error_handler(func=None, *, msg="", exe=Exception, response=None, log_error_msg=True):
|
||||
"""A decorator to handle errors in an async function.
|
||||
Args:
|
||||
func (callable, optional): The function to decorate. Defaults to None.
|
||||
msg (str, optional): The error message to log. Defaults to "".
|
||||
exe (Exception, optional): The exception to catch. Defaults to Exception.
|
||||
response (Any, optional): The response to return when an error occurs. Defaults to None.
|
||||
log_error_msg (bool, optional): If True, log the error message. Defaults to True.
|
||||
"""
|
||||
if func is None:
|
||||
return partial(error_handler, msg=msg, exe=exe, response=response, log_error_msg=log_error_msg)
|
||||
|
||||
@@ -72,6 +115,15 @@ def error_handler(func=None, *, msg="", exe=Exception, response=None, log_error_
|
||||
|
||||
|
||||
def error_handler_sync(func=None, *, msg="", exe=Exception, response=None, log_error_msg=True):
|
||||
"""A decorator to handle errors in a synchronous function.
|
||||
|
||||
Args:
|
||||
func (callable, optional): The function to decorate. Defaults to None.
|
||||
msg (str, optional): The error message to log. Defaults to "".
|
||||
exe (Exception, optional): The exception to catch. Defaults to Exception.
|
||||
response (Any, optional): The response to return when an error occurs. Defaults to None.
|
||||
log_error_msg (bool, optional): If True, log the error message. Defaults to True.
|
||||
"""
|
||||
if func is None:
|
||||
return partial(error_handler, msg=msg, exe=exe, response=response, log_error_msg=log_error_msg)
|
||||
|
||||
@@ -88,7 +140,15 @@ def error_handler_sync(func=None, *, msg="", exe=Exception, response=None, log_e
|
||||
return wrapper
|
||||
|
||||
|
||||
def round_down(value: int | float, base: int) -> int:
|
||||
def round_down(value: int | float, base: int) -> int | float:
|
||||
"""Round down a number to the nearest base.
|
||||
Args:
|
||||
value (int | float): The number to round down.
|
||||
base (int): The base to round down to.
|
||||
|
||||
Returns:
|
||||
(int | float): The rounded down number.
|
||||
"""
|
||||
return int(value) if value % base == 0 else int(value - (value % base))
|
||||
|
||||
|
||||
@@ -98,19 +158,28 @@ def round_up(value: int | float, base: int) -> int:
|
||||
|
||||
# noinspection PyShadowingNames
|
||||
def round_off(value: float, step: float, round_down: bool = False) -> float:
|
||||
"""Round off a number to the nearest step."""
|
||||
"""Round off a number to the nearest step.
|
||||
|
||||
Args:
|
||||
value (float): The number to round off.
|
||||
step (float): The step to round off to.
|
||||
round_down (bool, optional): If True, the number is rounded down otherwise it is rounded up. Defaults to False.
|
||||
|
||||
Returns:
|
||||
float: The rounded off number.
|
||||
"""
|
||||
with decimal.localcontext() as ctx:
|
||||
ctx.rounding = decimal.ROUND_DOWN if round_down else decimal.ROUND_UP
|
||||
return float(decimal.Decimal(str(value)).quantize(decimal.Decimal(str(step))))
|
||||
|
||||
|
||||
def async_cache(fun):
|
||||
"""A decorator to cache the result of an async function."""
|
||||
@wraps(fun)
|
||||
async def wrapper(*args, **kwargs):
|
||||
key = (args, frozenset(kwargs.items()))
|
||||
with wrapper.lock:
|
||||
if key not in wrapper.cache:
|
||||
# print(key)
|
||||
wrapper.cache[key] = await fun(*args, **kwargs)
|
||||
return wrapper.cache[key]
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ logger = getLogger(__name__)
|
||||
|
||||
class BackTestController:
|
||||
"""The controller for the backtesting engine.
|
||||
It also act's as a synchronizier for running multiple strategies (tasks) using a threading.Barrier primitive.
|
||||
It also acts as a synchronizer for running multiple strategies (tasks) using a threading.Barrier primitive.
|
||||
It handles the updating of open positions and close them when necessary.
|
||||
It handles the iterator for the backtesting engine and handles it movement in time by moving it to the next time step.
|
||||
|
||||
@@ -33,6 +33,7 @@ class BackTestController:
|
||||
if not hasattr(cls, "_instance"):
|
||||
cls._instance = super().__new__(cls)
|
||||
cls._instance.config = Config()
|
||||
cls._instance.config.backtest_controller = cls._instance
|
||||
cls._instance.barrier = Barrier(1)
|
||||
cls._instance.tasks = []
|
||||
return cls._instance
|
||||
|
||||
@@ -9,6 +9,7 @@ from .task_queue import TaskQueue
|
||||
logger = getLogger(__name__)
|
||||
Bot = TypeVar("Bot")
|
||||
BackTestEngine = TypeVar("BackTestEngine")
|
||||
BackTestController = TypeVar("BackTestController")
|
||||
|
||||
|
||||
class Config:
|
||||
@@ -28,6 +29,7 @@ class Config:
|
||||
task_queue: TaskQueue
|
||||
_backtest_engine: BackTestEngine
|
||||
bot: Bot
|
||||
backtest_controller: BackTestController
|
||||
_instance: Self
|
||||
mode: Literal["backtest", "live"]
|
||||
use_terminal_for_backtesting: bool
|
||||
@@ -54,9 +56,11 @@ class Config:
|
||||
if not hasattr(cls, "_instance"):
|
||||
cls._instance = super().__new__(cls)
|
||||
cls._instance.state = {}
|
||||
cls._instance.task_queue = TaskQueue()
|
||||
cls._instance.task_queue = TaskQueue(mode='infinite', workers=10)
|
||||
cls._instance.set_attributes(**cls._defaults)
|
||||
cls._instance._backtest_engine = None
|
||||
cls._instance.bot = None
|
||||
cls._instance.backtest_controller = None
|
||||
# cls._instance.load_config(**kwargs)
|
||||
return cls._instance
|
||||
|
||||
|
||||
@@ -123,7 +123,8 @@ class OrderType(Repr, IntEnum):
|
||||
Returns:
|
||||
int: integer value of opposite order type
|
||||
"""
|
||||
return {0: 1, 1: 0, 2: 3, 3: 2, 4: 5, 5: 4, 6: 7, 7: 6, 8: 8}[self]
|
||||
_type = {0: 1, 1: 0, 2: 3, 3: 2, 4: 5, 5: 4, 6: 7, 7: 6, 8: 8}[self]
|
||||
return OrderType(_type)
|
||||
|
||||
|
||||
class BookType(Repr, IntEnum):
|
||||
|
||||
@@ -83,10 +83,14 @@ class TaskQueue:
|
||||
except asyncio.QueueFull:
|
||||
logger.error("Queue is full")
|
||||
|
||||
async def worker(self):
|
||||
async def worker(self, wid=None):
|
||||
"""Worker function to run tasks in the queue."""
|
||||
while True:
|
||||
try:
|
||||
if self.mode == 'infinite' and self.queue.qsize() <= 1:
|
||||
dummy = QueueItem(self.dummy_task)
|
||||
self.add(item=dummy)
|
||||
|
||||
if isinstance(self.queue, asyncio.PriorityQueue):
|
||||
_, item = self.queue.get_nowait()
|
||||
else:
|
||||
@@ -96,6 +100,7 @@ class TaskQueue:
|
||||
await item.run()
|
||||
|
||||
self.queue.task_done()
|
||||
|
||||
self.priority_tasks.discard(item)
|
||||
|
||||
if self.stop and (self.on_exit == 'cancel' or len(self.priority_tasks) == 0):
|
||||
@@ -107,16 +112,15 @@ class TaskQueue:
|
||||
break
|
||||
|
||||
if self.mode == 'finite':
|
||||
self.stop = True
|
||||
break
|
||||
|
||||
# add dummy task to prevent worker from exiting
|
||||
sleep = QueueItem(asyncio.sleep, 1)
|
||||
self.add(item=sleep)
|
||||
await asyncio.sleep(self.worker_timeout)
|
||||
except Exception as err:
|
||||
logger.error("%s: Error occurred in worker", err)
|
||||
break
|
||||
|
||||
async def dummy_task(self):
|
||||
await asyncio.sleep(self.worker_timeout)
|
||||
|
||||
async def run(self, timeout: int = 0):
|
||||
"""Run the queue until all tasks are completed or the timeout is reached.
|
||||
|
||||
@@ -128,13 +132,13 @@ class TaskQueue:
|
||||
"""
|
||||
start = time.perf_counter()
|
||||
try:
|
||||
self.worker_tasks.extend([asyncio.create_task(self.worker()) for _ in range(self.workers)])
|
||||
self.worker_tasks.extend(asyncio.create_task(self.worker()) for _ in range(self.workers))
|
||||
timeout = timeout or self.timeout
|
||||
self.queue_task = asyncio.create_task(self.queue.join())
|
||||
|
||||
if timeout:
|
||||
await asyncio.wait_for(self.queue_task, timeout=timeout)
|
||||
self.stop = True
|
||||
|
||||
else:
|
||||
await self.queue_task
|
||||
|
||||
@@ -142,22 +146,26 @@ class TaskQueue:
|
||||
logger.warning("Timed out after %d seconds, %d tasks remaining",
|
||||
time.perf_counter() - start, self.queue.qsize())
|
||||
self.stop = True
|
||||
await self.clean_up()
|
||||
|
||||
except asyncio.CancelledError:
|
||||
self.stop = True
|
||||
await self.clean_up()
|
||||
|
||||
except Exception as err:
|
||||
logger.warning("%s: An error occurred in %s.run", err, self.__class__.__name__)
|
||||
self.stop = True
|
||||
await self.clean_up()
|
||||
|
||||
finally:
|
||||
await self.clean_up()
|
||||
print("Finally")
|
||||
|
||||
|
||||
async def clean_up(self):
|
||||
"""Clean up tasks in the queue, completing priority tasks if `on_exit` is `complete_priority`"""
|
||||
self.stop = True
|
||||
try:
|
||||
logger.info('cleaning up tasks...')
|
||||
|
||||
if self.on_exit == 'complete_priority' and (pt := len(self.priority_tasks)) > 0:
|
||||
logger.info('Completing %d priority tasks...', pt)
|
||||
self.queue_task = asyncio.create_task(self.queue.join())
|
||||
@@ -166,20 +174,16 @@ class TaskQueue:
|
||||
self.cancel()
|
||||
|
||||
except asyncio.CancelledError:
|
||||
self.stop = True
|
||||
self.cancel()
|
||||
|
||||
except Exception as err:
|
||||
logger.error(f"%s: Error occurred in %s", err, self.__class__.__name__)
|
||||
|
||||
finally:
|
||||
self.cancel()
|
||||
|
||||
def cancel(self):
|
||||
"""Cancel all tasks in the queue"""
|
||||
try:
|
||||
|
||||
self.queue_task.cancel()
|
||||
|
||||
except asyncio.CancelledError:
|
||||
...
|
||||
|
||||
@@ -188,8 +192,11 @@ class TaskQueue:
|
||||
|
||||
def sigint_handle(self, sig, frame):
|
||||
logger.info('SIGINT received, cleaning up...')
|
||||
self.stop = True
|
||||
self.cancel()
|
||||
if self.stop is False:
|
||||
self.stop = True
|
||||
else:
|
||||
self.stop = True
|
||||
self.cancel()
|
||||
|
||||
|
||||
TaskQueue.__doc__ = """TaskQueue is a class that allows you to queue tasks and run them concurrently with a specified number of workers.
|
||||
|
||||
@@ -38,7 +38,7 @@ class Account(_Base, AccountInfo):
|
||||
await self.mt5.initialize()
|
||||
self.connected = await self.mt5.login()
|
||||
if not self.connected:
|
||||
raise LoginError("Login failed")
|
||||
raise LoginError(f"Login failed: {self.mt5.error}")
|
||||
await self.refresh()
|
||||
return self
|
||||
|
||||
|
||||
@@ -183,6 +183,7 @@ class BackTester:
|
||||
self.executor.add_strategy(strategy=strategy)
|
||||
return True
|
||||
else:
|
||||
self.mt._symbol_select(strategy.symbol.name, True)
|
||||
self.mt._market_book_add(strategy.symbol.name)
|
||||
info = self.mt._symbol_info(strategy.symbol.name)
|
||||
time = datetime.fromtimestamp(self.backtest_engine.cursor.time, tz=UTC)
|
||||
|
||||
@@ -68,7 +68,7 @@ class Bot:
|
||||
|
||||
if len(self.executor.strategy_runners) == 0:
|
||||
logger.warning("No strategies were added to the bot. Exiting in five seconds")
|
||||
await asyncio.sleep(5)
|
||||
await asyncio.sleep(1)
|
||||
self.config.shutdown = True
|
||||
except Exception as err:
|
||||
logger.error("%s: Bot initialization failed", err)
|
||||
@@ -94,7 +94,7 @@ class Bot:
|
||||
|
||||
if len(self.executor.strategy_runners) == 0:
|
||||
logger.warning("No strategies were added to the bot. Exiting in 5 seconds")
|
||||
time.sleep(5)
|
||||
time.sleep(1)
|
||||
self.config.shutdown = True
|
||||
except Exception as err:
|
||||
logger.error("%s: Bot initialization failed", err)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import asyncio
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from typing import Coroutine, Callable
|
||||
import os
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from signal import signal, SIGINT
|
||||
from typing import Coroutine, Callable
|
||||
from logging import getLogger
|
||||
|
||||
from ..core.config import Config
|
||||
@@ -32,6 +33,7 @@ class Executor:
|
||||
self.tasks = []
|
||||
self.config = Config()
|
||||
self.timeout = None # Timeout for the executor. For testing purposes only
|
||||
signal(SIGINT, self.sigint_handle)
|
||||
|
||||
def add_function(self, *, function: Callable, kwargs: dict = None):
|
||||
kwargs = kwargs or {}
|
||||
@@ -40,6 +42,7 @@ class Executor:
|
||||
def add_coroutine(self, *, coroutine: Callable | Coroutine, kwargs: dict = None, on_separate_thread=False):
|
||||
kwargs = kwargs or {}
|
||||
coroutine = coroutine(**kwargs)
|
||||
print('coroutine', coroutine)
|
||||
self.coroutines.append(coroutine) if on_separate_thread is False else self.coroutine_threads.append(coroutine)
|
||||
|
||||
def add_strategies(self, *, strategies: tuple[Strategy]):
|
||||
@@ -79,8 +82,10 @@ class Executor:
|
||||
async def create_coroutines_task(self):
|
||||
""""""
|
||||
task = asyncio.create_task(asyncio.gather(*self.coroutines, return_exceptions=True))
|
||||
print('task', task)
|
||||
self.tasks.append(task)
|
||||
await task
|
||||
res = await task
|
||||
print('res', res)
|
||||
|
||||
def run_coroutine_tasks(self):
|
||||
"""Run all coroutines in the executor"""
|
||||
@@ -102,23 +107,40 @@ class Executor:
|
||||
except Exception as err:
|
||||
logger.error(f"Error: {err}. Unable to run function: {function.__name__}")
|
||||
|
||||
def sigint_handle(self, signum, frame):
|
||||
print("SIGINT")
|
||||
self.config.shutdown = True
|
||||
|
||||
async def exit(self):
|
||||
"""Shutdown the executor"""
|
||||
start = asyncio.get_event_loop().time()
|
||||
print('exit', start)
|
||||
try:
|
||||
while self.config.shutdown is False and self.config.force_shutdown is False:
|
||||
print('running exits')
|
||||
print("Timeout", self.timeout, asyncio.get_event_loop().time() - start)
|
||||
if self.timeout is not None and self.timeout < (asyncio.get_event_loop().time() - start):
|
||||
print("light Timeout", self.timeout, asyncio.get_event_loop().time() - start)
|
||||
self.config.shutdown = True
|
||||
|
||||
await asyncio.sleep(10)
|
||||
print('exiting')
|
||||
for strategy in self.strategy_runners:
|
||||
strategy.running = False
|
||||
for task in self.tasks:
|
||||
task.cancel()
|
||||
|
||||
if self.config.backtest_engine is not None:
|
||||
self.config.backtest_engine.stop_testing = True
|
||||
|
||||
self.executor.shutdown(wait=False, cancel_futures=True)
|
||||
|
||||
# for task in self.tasks:
|
||||
# task.cancel()
|
||||
|
||||
if self.config.force_shutdown:
|
||||
os._exit(1)
|
||||
except Exception as err:
|
||||
logger.error(f"Error: {err}. Unable to shutdown executor")
|
||||
print('error in timeout')
|
||||
# logger.error(f"Error: {err}. Unable to shutdown executor")
|
||||
os._exit(1)
|
||||
|
||||
def execute(self, *, workers: int = 5):
|
||||
"""Run the strategies with a threadpool executor.
|
||||
@@ -129,7 +151,7 @@ class Executor:
|
||||
Notes:
|
||||
No matter the number specified, the executor will always use a minimum of 5 workers.
|
||||
"""
|
||||
workers_ = len(self.strategy_runners) + len(self.functions) + len(self.coroutine_threads) + 2
|
||||
workers_ = len(self.strategy_runners) + len(self.functions) + len(self.coroutine_threads) + 3
|
||||
workers = max(workers, workers_)
|
||||
with ThreadPoolExecutor(max_workers=workers) as executor:
|
||||
self.executor = executor
|
||||
|
||||
@@ -28,6 +28,15 @@ class Order(_Base, TradeRequest):
|
||||
kwargs = {"action": TradeAction.DEAL, "type_time": OrderTime.DAY, "type_filling": OrderFilling.FOK, **kwargs}
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def modify(self, **kwargs):
|
||||
"""Modify the order object with keyword arguments.
|
||||
|
||||
Args:
|
||||
**kwargs: Keyword arguments must match the attributes of TradeRequest as well as the attributes of
|
||||
Order class as specified in the annotations in the class definition.
|
||||
"""
|
||||
self.set_attributes(**kwargs)
|
||||
|
||||
async def orders_total(self):
|
||||
"""Get the number of active pending orders.
|
||||
|
||||
|
||||
@@ -24,23 +24,38 @@ class Positions:
|
||||
|
||||
mt5: MetaTrader | MetaBackTester
|
||||
positions: tuple[TradePosition, ...]
|
||||
total_positions: int
|
||||
|
||||
def __init__(self):
|
||||
"""Get Open Positions"""
|
||||
self.config = Config()
|
||||
self.mt5 = MetaTrader() if self.config.mode != "backtest" else MetaBackTester()
|
||||
self.positions = ()
|
||||
self.total_positions = 0
|
||||
|
||||
@backoff_decorator
|
||||
async def get_positions(self) -> tuple[TradePosition, ...]:
|
||||
"""Get open positions with the ability to filter by symbol or ticket.
|
||||
async def get_positions(self, *, symbol: str = None, ticket: int = None, group: str = None) -> tuple[TradePosition, ...]:
|
||||
"""Get open positions with the ability to filter by symbol, ticket or group of symbols.
|
||||
Args:
|
||||
symbol (Optional[str]): Financial instrument name. If symbol is provided, ticket is ignored.
|
||||
ticket (Optional[int]): Position ticket.
|
||||
group (Optional[str]): Group of symbols.
|
||||
|
||||
Returns:
|
||||
tuple[TradePosition, ...]: A tuple of open trade positions
|
||||
"""
|
||||
positions = await self.mt5.positions_get()
|
||||
kwargs = {}
|
||||
if symbol is not None:
|
||||
kwargs["symbol"] = symbol
|
||||
ticket = None
|
||||
if ticket is not None:
|
||||
kwargs["ticket"] = ticket
|
||||
if group is not None:
|
||||
kwargs["group"] = group
|
||||
positions = await self.mt5.positions_get(**kwargs)
|
||||
if positions is not None:
|
||||
self.positions = tuple(TradePosition(**pos._asdict()) for pos in positions)
|
||||
self.total_positions = len(self.positions)
|
||||
return self.positions
|
||||
logger.warning("Failed to get open positions")
|
||||
return ()
|
||||
@@ -130,3 +145,9 @@ class Positions:
|
||||
*(self.close_position(position=position) for position in positions), return_exceptions=True
|
||||
)
|
||||
return len([res for res in results if (isinstance(res, OrderSendResult) and res.retcode == 10009)])
|
||||
|
||||
async def get_total_positions(self) -> int:
|
||||
"""Get total number of open positions."""
|
||||
total = await self.mt5.positions_total()
|
||||
self.total_positions = total or self.total_positions
|
||||
return self.total_positions
|
||||
|
||||
@@ -36,6 +36,11 @@ class RAM:
|
||||
self.open_limit = kwargs.get("open_limit", 3)
|
||||
self.fixed_amount = kwargs.get("fixed_amount", None)
|
||||
|
||||
def modify_ram(self, **kwargs):
|
||||
"""Modify the Risk Assessment and Management with the provided keyword arguments.
|
||||
"""
|
||||
[setattr(self, key, value) for key, value in kwargs.items()]
|
||||
|
||||
async def get_amount(self) -> float:
|
||||
"""Calculate the amount to risk per trade as a percentage of margin_free.
|
||||
|
||||
|
||||
@@ -78,7 +78,8 @@ class Result:
|
||||
"""Serialize the trade records and strategy parameters"""
|
||||
try:
|
||||
return str(value)
|
||||
except (ValueError, TypeError) as _:
|
||||
except Exception as err:
|
||||
logger.error("%s: Unable to serialize value", err)
|
||||
return ""
|
||||
|
||||
async def to_json(self):
|
||||
|
||||
@@ -5,8 +5,8 @@ from logging import getLogger
|
||||
|
||||
from ..core.models import OrderSendResult, TradePosition
|
||||
from ..core.config import Config
|
||||
from ..core.backtesting.backtest_controller import BackTestController
|
||||
from .positions import Positions
|
||||
from .._utils import backtest_sleep
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
@@ -26,13 +26,13 @@ def delta(obj: time) -> timedelta:
|
||||
return timedelta(hours=obj.hour, minutes=obj.minute, seconds=obj.second, microseconds=obj.microsecond)
|
||||
|
||||
|
||||
async def backtest_sleep(secs):
|
||||
"""An async sleep function for use during backtesting."""
|
||||
btc = BackTestController()
|
||||
config = Config()
|
||||
sleep = config.backtest_engine.cursor.time + secs
|
||||
while sleep > config.backtest_engine.cursor.time:
|
||||
btc.wait()
|
||||
# async def backtest_sleep(secs):
|
||||
# """An async sleep function for use during backtesting."""
|
||||
# btc = BackTestController()
|
||||
# config = Config()
|
||||
# sleep = config.backtest_engine.cursor.time + secs
|
||||
# while sleep > config.backtest_engine.cursor.time:
|
||||
# btc.wait()
|
||||
|
||||
|
||||
class Session:
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"login": 31288540,
|
||||
"password": "nwa0#anaEze",
|
||||
"server": "Deriv-Demo",
|
||||
"path": "./terminals/deriv/terminal64.exe",
|
||||
"default-password": "nwa0#anaEze",
|
||||
"demo": 5463204,
|
||||
"fin": 24251812,
|
||||
"deriv-demo": 5463204,
|
||||
"deriv-demo2": 31288540,
|
||||
"test-demo": 5400820,
|
||||
"test-password": "Gr@ndE1f",
|
||||
"mode": "live"
|
||||
}
|
||||
@@ -5,7 +5,8 @@ from aiomql.contrib.strategies import Chaos
|
||||
from aiomql.contrib.symbols import ForexSymbol
|
||||
|
||||
|
||||
async def test_bot():
|
||||
async def test_bot(capsys):
|
||||
print('testing')
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
syms = ["BTCUSD", "SOLUSD", "ETHUSD"]
|
||||
symbols = [ForexSymbol(name=sym) for sym in syms]
|
||||
@@ -14,6 +15,7 @@ async def test_bot():
|
||||
bot.config.task_queue.worker_timeout = 2
|
||||
bot.executor.timeout = 10
|
||||
bot.add_strategies(strategies=strategies)
|
||||
print(bot.executor.strategy_runners)
|
||||
await bot.initialize()
|
||||
bot.executor.execute()
|
||||
assert len(bot.executor.coroutines) == 1
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"login": 31288540,
|
||||
"password": "nwa0#anaEze",
|
||||
"server": "Deriv-Demo",
|
||||
"path": "./terminals/deriv/terminal64.exe",
|
||||
"default-password": "nwa0#anaEze",
|
||||
"demo": 5463204,
|
||||
"fin": 24251812,
|
||||
"deriv-demo": 5463204,
|
||||
"deriv-demo2": 31288540,
|
||||
"test-demo": 5400820,
|
||||
"test-password": "Gr@ndE1f",
|
||||
"mode": "live"
|
||||
}
|
||||
Reference in New Issue
Block a user