Skip to content

Commit

Permalink
feat(plugins): implemented mbp plugin
Browse files Browse the repository at this point in the history
Implemented and tested mbp plugin. Pretty cool, the value is calculated after the order is applied. Fisrt time since the start of the project that this is possible.
  • Loading branch information
tomjeannesson committed Aug 13, 2023
1 parent 1590f1f commit 0bf8431
Show file tree
Hide file tree
Showing 21 changed files with 310 additions and 44 deletions.
56 changes: 56 additions & 0 deletions django_napse/core/migrations/0002_plugin_mbpplugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Generated by Django 4.1.7 on 2023-08-13 18:39

from django.db import migrations, models
import django.db.models.deletion
import django_napse.utils.findable_class


class Migration(migrations.Migration):

dependencies = [
("django_napse_core", "0001_initial"),
]

operations = [
migrations.CreateModel(
name="Plugin",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("category", models.CharField(max_length=255)),
(
"strategy",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="plugins",
to="django_napse_core.strategy",
),
),
],
bases=(models.Model, django_napse.utils.findable_class.FindableClass),
),
migrations.CreateModel(
name="MBPPlugin",
fields=[
(
"plugin_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="django_napse_core.plugin",
),
),
],
bases=("django_napse_core.plugin",),
),
]
2 changes: 2 additions & 0 deletions django_napse/core/models/bots/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
from .config import *
from .controller import *
from .implementations import *
from .plugin import *
from .plugins import *
from .strategy import *
10 changes: 7 additions & 3 deletions django_napse/core/models/bots/architecture.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.db import models

from django_napse.core.models.bots.managers import ArchitectureManager
from django_napse.utils.constants import ORDER_LEEWAY_PERCENTAGE, SIDES
from django_napse.utils.constants import ORDER_LEEWAY_PERCENTAGE, PLUGIN_CATEGORIES, SIDES
from django_napse.utils.errors.orders import OrderError
from django_napse.utils.findable_class import FindableClass

Expand Down Expand Up @@ -72,7 +72,7 @@ def prepare_db_data(self):
"controllers": self.controllers_dict(),
"connections": self.strategy.bot.get_connections(),
"connection_data": self.strategy.bot.get_connection_data(),
# "plugins": self.strategy.plugins.all(),
"plugins": {category: self.strategy.plugins.filter(category=category) for category in PLUGIN_CATEGORIES},
}

def _get_orders(self, data: dict, no_db_data: Optional[dict] = None) -> list[dict]:
Expand All @@ -84,11 +84,15 @@ def _get_orders(self, data: dict, no_db_data: Optional[dict] = None) -> list[dic
all_orders = []
for connection in connections:
new_data = {**data, **no_db_data, "connection": connection}

# pprint(new_data)
if architecture.skip(data=new_data):
continue
for plugin in no_db_data["plugins"][PLUGIN_CATEGORIES.PRE_ORDER]:
plugin.apply(data=new_data)
orders = strategy.give_order(data=new_data)
for order in orders:
for plugin in no_db_data["plugins"][PLUGIN_CATEGORIES.POST_ORDER]:
plugin.apply(data={**new_data, "order": order})
order["StrategyModifications"] += architecture.strategy_modifications(order=order, data=new_data)
order["ConnectionModifications"] += architecture.connection_modifications(order=order, data=new_data)
order["ArchitectureModifications"] += architecture.architecture_modifications(order=order, data=new_data)
Expand Down
5 changes: 4 additions & 1 deletion django_napse/core/models/bots/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ def _get_orders(self, data: Optional[dict] = None, no_db_data: Optional[dict] =
return self.architecture._get_orders(data=data, no_db_data=no_db_data)

def connect_to(self, wallet):
return Connection.objects.create(owner=wallet, bot=self)
connection = Connection.objects.create(owner=wallet, bot=self)
for plugin in self._strategy.plugins.all():
plugin.connect(connection)
return connection

def copy(self):
return self.__class__.objects.create(
Expand Down
34 changes: 29 additions & 5 deletions django_napse/core/models/bots/implementations/empty/strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,52 @@ def info(self, verbose=True, beacon=""):
def give_order(self, data: dict) -> list[dict]:
controller = data["controllers"]["main"]
return [
# {
# "controller": controller,
# "ArchitectureModifications": [],
# "StrategyModifications": [],
# "ConnectionModifications": [],
# "connection": data["connection"],
# "asked_for_amount": 0,
# "asked_for_ticker": controller.quote,
# "pair": controller.pair,
# "price": data["candles"][controller]["latest"]["close"],
# "side": SIDES.KEEP,
# },
# {
# "controller": controller,
# "ArchitectureModifications": [],
# "StrategyModifications": [],
# "ConnectionModifications": [],
# "connection": data["connection"],
# "asked_for_amount": 15 / data["candles"][controller]["latest"]["close"],
# "asked_for_ticker": controller.base,
# "pair": controller.pair,
# "price": data["candles"][controller]["latest"]["close"],
# "side": SIDES.SELL,
# },
{
"controller": controller,
"ArchitectureModifications": [],
"StrategyModifications": [],
"ConnectionModifications": [],
"connection": data["connection"],
"asked_for_amount": 0,
"asked_for_amount": 15,
"asked_for_ticker": controller.quote,
"pair": controller.pair,
"price": data["candles"][controller]["latest"]["close"],
"side": SIDES.KEEP,
"side": SIDES.BUY,
},
{
"controller": controller,
"ArchitectureModifications": [],
"StrategyModifications": [],
"ConnectionModifications": [],
"connection": data["connection"],
"asked_for_amount": 15 / data["candles"][controller]["latest"]["close"],
"asked_for_ticker": controller.base,
"asked_for_amount": 20,
"asked_for_ticker": controller.quote,
"pair": controller.pair,
"price": data["candles"][controller]["latest"]["close"],
"side": SIDES.SELL,
"side": SIDES.BUY,
},
]
6 changes: 3 additions & 3 deletions django_napse/core/models/bots/managers/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

class PluginManager(models.Manager):
def create(self, strategy):
if self.plugin_category not in PLUGIN_CATEGORIES:
error_msg = f"Invalid plugin category: {self.plugin_category}"
if self.model.plugin_category() not in PLUGIN_CATEGORIES:
error_msg = f"Invalid plugin category: {self.model.plugin_category()}"
raise PluginError.InvalidPluginCategory(error_msg)
plugin = self.model(strategy=strategy, category=self.plugin_category)
plugin = self.model(strategy=strategy, category=self.model.plugin_category())
plugin.save()
return plugin
27 changes: 23 additions & 4 deletions django_napse/core/models/bots/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,32 @@ class Plugin(models.Model, FindableClass):
def __str__(self):
return f"PLUGIN {self.pk=}"

@property
def plugin_category(self):
if self.__class__ == Plugin:
def info(self, verbose=True, beacon=""):
string = ""
string += f"{beacon}Plugin {self.pk}:\n"
string += f"{beacon}Args:\n"
string += f"{beacon}\t{self.category=}\n"
return string

@classmethod
def plugin_category(cls):
if cls == Plugin:
error_msg = "plugin_category not implemented for the Plugin base class, please implement it in a subclass."
else:
error_msg = f"plugin_category not implemented for the Plugin base class, please implement it in the {self.__class__} class."
error_msg = f"plugin_category not implemented for the Plugin base class, please implement it in the {cls} class."
raise NotImplementedError(error_msg)

def _connect(self, connection):
if self.__class__ == Plugin:
error_msg = "connect not implemented for the Plugin base class, please implement it in a subclass."
else:
error_msg = f"connect not implemented for the Plugin base class, please implement it in the {self.__class__} class."
raise NotImplementedError(error_msg)

def connect(self, connection):
self = self.find()
return self._connect(connection)

def _apply(self, data: dict) -> dict:
if self.__class__ == Plugin:
error_msg = "_apply not implemented for the Plugin base class, please implement it in a subclass."
Expand All @@ -29,4 +47,5 @@ def _apply(self, data: dict) -> dict:
raise NotImplementedError(error_msg)

def apply(self, data: dict) -> dict:
self = self.find()
return self._apply(data)
26 changes: 21 additions & 5 deletions django_napse/core/models/bots/plugins/mbp.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
from django_napse.core.models.bots.plugin import Plugin
from django_napse.utils.constants import PLUGIN_CATEGORIES
from django_napse.core.models.connections.connection import ConnectionSpecificArgs
from django_napse.utils.constants import PLUGIN_CATEGORIES, SIDES


class MBPPlugin(Plugin):
@property
def plugin_category(self):
return PLUGIN_CATEGORIES.PRE_PROCESSING
@classmethod
def plugin_category(cls):
return PLUGIN_CATEGORIES.POST_ORDER

def _apply(self, data: dict) -> dict:
return super()._apply(data)
order = data["order"]
if order["side"] == SIDES.BUY:
new_mbp = f"{order['controller'].base}|($ * _ + #) / (# / {order['price']} + $)"
order["ConnectionModifications"] += [
{
"key": "mbp",
"value": new_mbp,
"target_type": "plugin_mbp",
"ignore_failed_order": False,
"connection_specific_arg": data["connection_data"][data["connection"]]["connection_specific_args"]["mbp"],
},
]
return data

def _connect(self, connection):
ConnectionSpecificArgs.objects.create(connection=connection, key="mbp", value="0", target_type="float")
7 changes: 6 additions & 1 deletion django_napse/core/models/bots/strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ def architecture_class(cls):
return cls._meta.get_field("architecture").related_model

def copy(self):
return self.find().__class__.objects.create(
new_strategy = self.find().__class__.objects.create(
config=self.config.duplicate_immutable(),
architecture=self.architecture.copy(),
)

for plugin in self.plugins.all():
plugin = plugin.find()
plugin.__class__.objects.create(strategy=new_strategy)
return new_strategy
18 changes: 17 additions & 1 deletion django_napse/core/models/connections/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django_napse.core.models.connections.managers import ConnectionManager
from django_napse.core.models.transactions.transaction import Transaction
from django_napse.utils.constants import TRANSACTION_TYPES
from django_napse.utils.usefull_functions import process_value_from_type


class Connection(models.Model):
Expand Down Expand Up @@ -73,7 +74,7 @@ def to_dict(self):
return {
"connection": self,
"wallet": self.wallet.find().to_dict(),
"connection_specific_args": self.specific_args.all(),
"connection_specific_args": {arg.key: arg for arg in self.specific_args.all()},
}


Expand All @@ -89,3 +90,18 @@ class Meta:
def __str__(self): # pragma: no cover
string = f"CONNECTION_SPECIFIC_ARGS: {self.pk=},"
return string + f"connection__pk={self.connection.pk}, key={self.key}, value={self.value}, target_type={self.target_type}"

def info(self, verbose=True, beacon=""):
string = ""
string += f"{beacon}ConnectionSpecificArgs {self.pk}:\n"
string += f"{beacon}Args:\n"
string += f"{beacon}\t{self.connection=}\n"
string += f"{beacon}\t{self.key=}\n"
string += f"{beacon}\t{self.value=}\n"
string += f"{beacon}\t{self.target_type=}\n"
if verbose: # pragma: no cover
print(string)
return string

def get_value(self):
return process_value_from_type(self.value, self.target_type)
3 changes: 2 additions & 1 deletion django_napse/core/models/modifications/architecture.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class ArchitectureModification(Modification):
def apply(self):
architecture = self.order.connection.bot.architecture.find()
self._apply(architecture)
architectur, self = self._apply(architecture)
architecture.save()
self.save()

Expand All @@ -19,3 +19,4 @@ def _apply(self, **kwargs):

setattr(architecture, f"variable_{self.key}", process_value_from_type(self.value, self.target_type))
self.status = MODIFICATION_STATUS.APPLIED
return architecture, self
7 changes: 4 additions & 3 deletions django_napse/core/models/modifications/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ class ConnectionModification(Modification):
connection_specific_arg = models.ForeignKey("ConnectionSpecificArgs", on_delete=models.CASCADE, related_name="modifications")

def apply(self):
self._apply(None)
self.connection_specific_arg.save()
connection_specific_arg, self = self._apply()
connection_specific_arg.save()
self.save()

def _apply(self, **kwargs):
self.connection_specific_arg.value = self.value
self.connection_specific_arg.value = self.get_value(current_value=self.connection_specific_arg.get_value(), **kwargs)
self.status = MODIFICATION_STATUS.APPLIED
return self.connection_specific_arg, self
4 changes: 4 additions & 0 deletions django_napse/core/models/modifications/modification.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from django_napse.utils.constants import MODIFICATION_STATUS
from django_napse.utils.findable_class import FindableClass
from django_napse.utils.usefull_functions import process_value_from_type


class Modification(models.Model, FindableClass):
Expand All @@ -17,3 +18,6 @@ class Modification(models.Model, FindableClass):

def __str__(self) -> str:
return f"MODIFICATION: {self.pk=}"

def get_value(self, **kwargs):
return process_value_from_type(self.value, self.target_type, **kwargs)
3 changes: 2 additions & 1 deletion django_napse/core/models/modifications/strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class StrategyModification(Modification):
def apply(self):
strategy = self.order.connection.bot.strategy.find()
self._apply(strategy)
strategy, self = self._apply(strategy)
strategy.save()
self.save()

Expand All @@ -18,3 +18,4 @@ def _apply(self, **kwargs):
raise ValueError(error_msg)
setattr(strategy, f"variable_{self.key}", process_value_from_type(self.value, self.target_type))
self.status = MODIFICATION_STATUS.APPLIED
return strategy, self
Loading

0 comments on commit 0bf8431

Please sign in to comment.