Skip to content

Commit

Permalink
actor
Browse files Browse the repository at this point in the history
  • Loading branch information
m5l14i11 committed Aug 18, 2023
1 parent 1c0fd30 commit a24c210
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 33 deletions.
23 changes: 23 additions & 0 deletions strategy_management/abstract_actor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from abc import abstractmethod

from core.abstract_event_manager import AbstractEventManager
from core.events.ohlcv import OHLCV


class AbsctractActor(AbstractEventManager):
@property
@abstractmethod
def id(self) -> str:
pass

@abstractmethod
def start(self):
pass

@abstractmethod
def stop(self):
pass

@abstractmethod
def next(self, data: OHLCV):
pass
9 changes: 9 additions & 0 deletions strategy_management/abstract_strategy_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from abc import abstractmethod

from .abstract_actor import AbsctractActor


class AbsctractStrategyActorFactory:
@abstractmethod
def create_actor(self, wasm_path: str, strategy: str, paremeters: tuple[int]) -> AbsctractActor:
pass
93 changes: 60 additions & 33 deletions strategy_management/strategy_actor.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,83 @@
import asyncio
import ctypes
from core.events.ohlcv import OHLCV
from wasmtime import Memory, Store, Linker, WasiConfig, Module
from enum import Enum
from wasmtime import Memory, Store, Linker, Module

class StrategyActor:
def __init__(self, strategy: str, linker: Linker, store: Store, module: Module):
from core.events.strategy import ExitLongSignalReceived, ExitShortSignalReceived, GoLongSignalReceived, GoShortSignalReceived
from core.events.ohlcv import NewMarketDataReceived

from .abstract_actor import AbsctractActor


class Action(Enum):
GO_LONG = 1.0
GO_SHORT = 2.0
EXIT_LONG = 3.0
EXIT_SHORT = 4.0


class StrategyActor(AbsctractActor):
def __init__(self, strategy: str, parameters: tuple[int], linker: Linker, store: Store, module: Module):
super().__init__()
self.strategy = strategy
self.parameters = parameters
self.store = store
self.instance = linker.instantiate(self.store, module)
self.strategy_id = None
self.strategy = strategy

def start(self, *args):
self.strategy_id = self.instance.exports(self.store)[f"register_{self.strategy}"](self.store, *args)
@property
def id(self):
if self.strategy_id is None:
raise RuntimeError("Strategy is not started")

exports = self.instance.exports(self.store)
params = exports["strategy_parameters"](self.store, self.strategy_id)
memory = exports["memory"]

return self._get_string_from_memory(self.store, memory, params[0], params[1])

def start(self):
if self.strategy_id:
raise RuntimeError("Strategy is running")

self.strategy_id = self.instance.exports(self.store)[f"register_{self.strategy}"](self.store, *self.parameters)
self.dispatcher.register(NewMarketDataReceived, self.next)

def stop(self):
if self.strategy_id is None:
raise RuntimeError("Strategy is not started")

self.instance.exports(self.store)[f"unregister_strategy"](self.store, self.strategy_id)
self.strategy_id = None
self.dispatcher.unregister(NewMarketDataReceived, self.next)

def next(self, data: OHLCV):
async def next(self, event: NewMarketDataReceived):
if self.strategy_id is None:
raise RuntimeError("Strategy is not started")

strategy_next = self.instance.exports(self.store)["strategy_next"]
strategy_stop_loss = self.instance.exports(self.store)["strategy_stop_loss"]

result = strategy_next(self.store, self.strategy_id, data.open, data.high, data.low, data.close, data.volume)
data = event.ohlcv
symbol = event.symbol
timeframe = event.timeframe

return result

@property
def id(self):
if self.strategy_id is None:
raise RuntimeError("Strategy is not started")
[action, price] = strategy_next(self.store, self.strategy_id, data.open, data.high, data.low, data.close, data.volume)
[long_stop_loss, short_stop_loss] = strategy_stop_loss(self.store, self.strategy_id)

exports = self.instance.exports(self.store)
params = exports["strategy_parameters"](self.store, self.strategy_id)
memory = exports["memory"]
tasks = []

return self._get_string_from_memory(self.store, memory, params[0], params[1])
match action:
case Action.GO_LONG.value: tasks.append(self.dispatcher.dispatch(
GoLongSignalReceived(symbol=symbol, strategy=self.id, timeframe=timeframe, entry=price, stop_loss=long_stop_loss)))
case Action.GO_SHORT.value: tasks.append(self.dispatcher.dispatch(
GoShortSignalReceived(symbol=symbol, strategy=self.id, timeframe=timeframe, entry=price, stop_loss=short_stop_loss)))
case Action.EXIT_LONG.value: tasks.append(self.dispatcher.dispatch(
ExitLongSignalReceived(symbol=symbol, strategy=self.id, timeframe=timeframe, exit=event.ohlcv.close)))
case Action.EXIT_SHORT.value: tasks.append(self.dispatcher.dispatch(
ExitShortSignalReceived(symbol=symbol, strategy=self.id, timeframe=timeframe, exit=event.ohlcv.close)))

await asyncio.gather(*tasks)

@staticmethod
def _get_string_from_memory(store: Store, memory: Memory, pointer, length):
Expand All @@ -50,17 +89,5 @@ def _get_string_from_memory(store: Store, memory: Memory, pointer, length):
raise ValueError("Pointer and length exceed memory bounds")

byte_array = (ctypes.c_char * length).from_address(final_address)

return byte_array.value.decode('utf-8')

class StrategyActorFactory:
def __init__(self):
self.store = Store()
self.linker = Linker(self.store.engine)
wasi_config = WasiConfig()
self.store.set_wasi(wasi_config)
self.linker.define_wasi()

def create_actor(self, wasm_path, strategy):
module = Module.from_file(self.store.engine, wasm_path)
return StrategyActor(strategy, self.linker, self.store, module)
return byte_array.value.decode('utf-8')
19 changes: 19 additions & 0 deletions strategy_management/strategy_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from wasmtime import Store, Linker, WasiConfig, Module

from .abstract_strategy_factory import AbsctractStrategyActorFactory
from .strategy_actor import StrategyActor


class StrategyActorFactory(AbsctractStrategyActorFactory):
def __init__(self):
self.store = Store()
self.linker = Linker(self.store.engine)
wasi_config = WasiConfig()
wasi_config.wasm_multi_value = True
self.store.set_wasi(wasi_config)
self.linker.define_wasi()

def create_actor(self, wasm_path, strategy, parameters):
module = Module.from_file(self.store.engine, wasm_path)

return StrategyActor(strategy, parameters, self.linker, self.store, module)

0 comments on commit a24c210

Please sign in to comment.