diff --git a/freqtrade/aws/schemas.py b/freqtrade/aws/schemas.py index 139597f9c..7838b5b8f 100644 --- a/freqtrade/aws/schemas.py +++ b/freqtrade/aws/schemas.py @@ -1,2 +1,55 @@ - - +# defines the schema to submit a new strategy to the system +__SUBMIT_STRATEGY_SCHEMA__ = { + "$id": "http://example.com/example.json", + "type": "object", + "definitions": {}, + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "user": { + "$id": "/properties/user", + "type": "string", + "title": "the associated Isaac user", + "default": "", + "examples": [ + "GCU4LW2XXZW3A3FM2XZJTEJHNWHTWDKY2DIJLCZJ5ULVZ4K7LZ7D23TG" + ] + }, + "description": { + "$id": "/properties/description", + "type": "string", + "title": "a brief description", + "default": "", + "examples": [ + "simple test strategy" + ] + }, + "name": { + "$id": "/properties/name", + "type": "string", + "title": "the name of your strategy", + "default": "", + "examples": [ + "TestStrategy" + ] + }, + "public": { + "$id": "/properties/public", + "type": "boolean", + "title": "Will this strategy be public", + "default": "false", + "examples": [ + "true", + "false" + ] + }, + "content": { + "$id": "/properties/content", + "type": "string", + "title": "The Content Schema ", + "default": "", + "examples": [ + "IyAtLS0gRG8gbm90IHJlbW92ZSB0aGVzZSBsaWJzIC0tLQpmcm9tIGZyZXF0cmFkZS5zdHJhdGVneS5pbnRlcmZhY2UgaW1wb3J0IElTdHJhdGVneQpmcm9tIHR5cGluZyBpbXBvcnQgRGljdCwgTGlzdApmcm9tIGh5cGVyb3B0IGltcG9ydCBocApmcm9tIGZ1bmN0b29scyBpbXBvcnQgcmVkdWNlCmZyb20gcGFuZGFzIGltcG9ydCBEYXRhRnJhbWUKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKaW1wb3J0IHRhbGliLmFic3RyYWN0IGFzIHRhCmltcG9ydCBmcmVxdHJhZGUudmVuZG9yLnF0cHlsaWIuaW5kaWNhdG9ycyBhcyBxdHB5bGliCgpjbGFzcyBUZXN0U3RyYXRlZ3koSVN0cmF0ZWd5KToKICAgIG1pbmltYWxfcm9pID0gewogICAgICAgICIwIjogMC41CiAgICB9CiAgICBzdG9wbG9zcyA9IC0wLjIKICAgIHRpY2tlcl9pbnRlcnZhbCA9ICc1bScKCiAgICBkZWYgcG9wdWxhdGVfaW5kaWNhdG9ycyhzZWxmLCBkYXRhZnJhbWU6IERhdGFGcmFtZSkgLT4gRGF0YUZyYW1lOgogICAgICAgIG1hY2QgPSB0YS5NQUNEKGRhdGFmcmFtZSkKICAgICAgICBkYXRhZnJhbWVbJ21hU2hvcnQnXSA9IHRhLkVNQShkYXRhZnJhbWUsIHRpbWVwZXJpb2Q9OCkKICAgICAgICBkYXRhZnJhbWVbJ21hTWVkaXVtJ10gPSB0YS5FTUEoZGF0YWZyYW1lLCB0aW1lcGVyaW9kPTIxKQogICAgICAgIHJldHVybiBkYXRhZnJhbWUKCiAgICBkZWYgcG9wdWxhdGVfYnV5X3RyZW5kKHNlbGYsIGRhdGFmcmFtZTogRGF0YUZyYW1lKSAtPiBEYXRhRnJhbWU6CiAgICAgICAgZGF0YWZyYW1lLmxvY1sKICAgICAgICAgICAgKAogICAgICAgICAgICAgICAgcXRweWxpYi5jcm9zc2VkX2Fib3ZlKGRhdGFmcmFtZVsnbWFTaG9ydCddLCBkYXRhZnJhbWVbJ21hTWVkaXVtJ10pCiAgICAgICAgICAgICksCiAgICAgICAgICAgICdidXknXSA9IDEKCiAgICAgICAgcmV0dXJuIGRhdGFmcmFtZQoKICAgIGRlZiBwb3B1bGF0ZV9zZWxsX3RyZW5kKHNlbGYsIGRhdGFmcmFtZTogRGF0YUZyYW1lKSAtPiBEYXRhRnJhbWU6CiAgICAgICAgZGF0YWZyYW1lLmxvY1sKICAgICAgICAgICAgKAogICAgICAgICAgICAgICAgcXRweWxpYi5jcm9zc2VkX2Fib3ZlKGRhdGFmcmFtZVsnbWFNZWRpdW0nXSwgZGF0YWZyYW1lWydtYVNob3J0J10pCiAgICAgICAgICAgICksCiAgICAgICAgICAgICdzZWxsJ10gPSAxCiAgICAgICAgcmV0dXJuIGRhdGFmcmFtZQoKCiAgICAgICAg" + ] + } + } +} diff --git a/freqtrade/aws/strategy.py b/freqtrade/aws/strategy.py index 5816411fd..d1c7bae6b 100644 --- a/freqtrade/aws/strategy.py +++ b/freqtrade/aws/strategy.py @@ -1,3 +1,9 @@ +from freqtrade.strategy.resolver import StrategyResolver + +import simplejson as json +from jsonschema import validate +from freqtrade.aws.schemas import __SUBMIT_STRATEGY_SCHEMA__ +from base64 import urlsafe_b64decode def names(event, context): """ @@ -31,9 +37,23 @@ def code(event, context): def submit(event, context): """ - combiles the given strategy and stores it in the internal database + compiles the given strategy and stores it in the internal database :param event: :param context: :return: """ + + # get data + data = json.loads(event['body']) + + # validate against schema + validate(data, __SUBMIT_STRATEGY_SCHEMA__) + + strategy = urlsafe_b64decode(data['content']).decode('utf-8') + + # try to load the strategy + StrategyResolver().compile(data['name'], strategy) + + # save to DB + pass diff --git a/freqtrade/strategy/resolver.py b/freqtrade/strategy/resolver.py index 6df763a67..fbab1eb12 100644 --- a/freqtrade/strategy/resolver.py +++ b/freqtrade/strategy/resolver.py @@ -63,6 +63,13 @@ class StrategyResolver(object): key=lambda t: t[0])) self.strategy.stoploss = float(self.strategy.stoploss) + def compile(self, strategy_name: str, strategy_content: str) -> Optional[IStrategy]: + temp = Path(tempfile.mkdtemp("freq", "strategy")) + temp.joinpath(strategy_name + ".py").write_text(strategy_content) + temp.joinpath("__init__.py").touch() + + return self._load_strategy(strategy_name, temp.absolute()) + def _load_strategy( self, strategy_name: str, extra_dir: Optional[str] = None) -> Optional[IStrategy]: """ diff --git a/freqtrade/tests/aws/test_strategy_lambda.py b/freqtrade/tests/aws/test_strategy_lambda.py new file mode 100644 index 000000000..a8cea33d9 --- /dev/null +++ b/freqtrade/tests/aws/test_strategy_lambda.py @@ -0,0 +1,62 @@ +import simplejson as json +from base64 import urlsafe_b64encode +from freqtrade.aws.strategy import submit + + +def test_strategy(lambda_context): + content = """# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from typing import Dict, List +from hyperopt import hp +from functools import reduce +from pandas import DataFrame +# -------------------------------- + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +class TestStrategy(IStrategy): + minimal_roi = { + "0": 0.5 + } + stoploss = -0.2 + ticker_interval = '5m' + + def populate_indicators(self, dataframe: DataFrame) -> DataFrame: + macd = ta.MACD(dataframe) + dataframe['maShort'] = ta.EMA(dataframe, timeperiod=8) + dataframe['maMedium'] = ta.EMA(dataframe, timeperiod=21) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame: + dataframe.loc[ + ( + qtpylib.crossed_above(dataframe['maShort'], dataframe['maMedium']) + ), + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame: + dataframe.loc[ + ( + qtpylib.crossed_above(dataframe['maMedium'], dataframe['maShort']) + ), + 'sell'] = 1 + return dataframe + + + """ + + request = { + "user": "GCU4LW2XXZW3A3FM2XZJTEJHNWHTWDKY2DIJLCZJ5ULVZ4K7LZ7D23TG", + "description": "simple test strategy", + "name": "TestStrategy", + "content": urlsafe_b64encode(content.encode('utf-8')), + "public": False + } + + + submit({ + "body": json.dumps(request) + }, {})