added some more testing as well as cron expression is now scheduling larger intervals
This commit is contained in:
parent
19a525265f
commit
473339f740
@ -72,7 +72,7 @@ def backtest(event, context):
|
|||||||
refresh = True
|
refresh = True
|
||||||
|
|
||||||
if 'refresh' in event['body']:
|
if 'refresh' in event['body']:
|
||||||
refresh = event['body']
|
refresh = event['body']['refresh']
|
||||||
|
|
||||||
print("time range between dates is: {} days".format(timerange))
|
print("time range between dates is: {} days".format(timerange))
|
||||||
|
|
||||||
@ -96,14 +96,12 @@ def backtest(event, context):
|
|||||||
if "local" in event['body'] and event['body']['local']:
|
if "local" in event['body'] and event['body']['local']:
|
||||||
print("running in local mode")
|
print("running in local mode")
|
||||||
run_backtest(configuration, name, user, ticker, timerange)
|
run_backtest(configuration, name, user, ticker, timerange)
|
||||||
return {
|
|
||||||
"statusCode": 200
|
|
||||||
}
|
|
||||||
else:
|
else:
|
||||||
print("running in remote mode")
|
print("running in remote mode")
|
||||||
|
json.dumps(_submit_job(configuration, user, ticker, timerange))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"statusCode": 200,
|
"statusCode": 200
|
||||||
"body": json.dumps(_submit_job(configuration, user, ticker, timerange))
|
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
return {
|
return {
|
||||||
@ -340,25 +338,22 @@ def cron(event, context):
|
|||||||
for i in response['Items']:
|
for i in response['Items']:
|
||||||
# fire a message to our queue
|
# fire a message to our queue
|
||||||
|
|
||||||
|
# we want to evaluate several time spans for the strategy
|
||||||
|
for day in [1, 7, 30, 90]:
|
||||||
|
|
||||||
|
# we want to evaluate several time intervals for each strategy
|
||||||
|
for interval in ['5m', '15m', '30m', '1h']:
|
||||||
message = {
|
message = {
|
||||||
"user": i['user'],
|
"user": i['user'],
|
||||||
"name": i['name'],
|
"name": i['name'],
|
||||||
"assets": i['assets'],
|
"assets": i['assets'],
|
||||||
"stake_currency": i['stake_currency']
|
"stake_currency": i['stake_currency'],
|
||||||
|
"local": False,
|
||||||
|
"refresh": True,
|
||||||
|
"ticker": interval,
|
||||||
|
"days": day
|
||||||
}
|
}
|
||||||
|
|
||||||
# triggered over html, let's provide
|
|
||||||
# a date range for the backtesting
|
|
||||||
if 'pathParameters' in event:
|
|
||||||
if 'from' in event['pathParameters']:
|
|
||||||
message['from'] = event['pathParameters']['from']
|
|
||||||
else:
|
|
||||||
message['from'] = datetime.datetime.today().strftime('%Y%m%d')
|
|
||||||
if 'till' in event['pathParameters']:
|
|
||||||
message['till'] = event['pathParameters']['till']
|
|
||||||
else:
|
|
||||||
message['till'] = (datetime.datetime.today() - datetime.timedelta(days=1)).strftime('%Y%m%d')
|
|
||||||
|
|
||||||
serialized = json.dumps(message, use_decimal=True)
|
serialized = json.dumps(message, use_decimal=True)
|
||||||
# submit item to queue for routing to the correct persistence
|
# submit item to queue for routing to the correct persistence
|
||||||
|
|
||||||
|
@ -278,56 +278,3 @@ def submit_github(event, context):
|
|||||||
"statusCode": 404,
|
"statusCode": 404,
|
||||||
"body": json.dumps({"error": result})
|
"body": json.dumps({"error": result})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_trades(event, context):
|
|
||||||
"""
|
|
||||||
this function retuns all the knowns trades for a user, strategy and pair
|
|
||||||
:param event:
|
|
||||||
:param context:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
assert 'pathParameters' in event
|
|
||||||
assert 'user' in event['pathParameters']
|
|
||||||
assert 'name' in event['pathParameters']
|
|
||||||
assert 'stake' in event['pathParameters']
|
|
||||||
assert 'asset' in event['pathParameters']
|
|
||||||
|
|
||||||
table = get_trade_table()
|
|
||||||
|
|
||||||
response = table.query(
|
|
||||||
KeyConditionExpression=Key('id').eq(
|
|
||||||
"{}.{}:{}/{}".format(
|
|
||||||
event['pathParameters']['user'],
|
|
||||||
event['pathParameters']['name'],
|
|
||||||
event['pathParameters']['asset'].upper(),
|
|
||||||
event['pathParameters']['stake'].upper()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if "Items" in response and len(response['Items']) > 0:
|
|
||||||
|
|
||||||
# preparation for pagination
|
|
||||||
# TODO include in parameters an optional
|
|
||||||
# start key ExclusiveStartKey=response['LastEvaluatedKey']
|
|
||||||
|
|
||||||
data = {
|
|
||||||
"result": response['Items'],
|
|
||||||
"paginationKey": response.get('LastEvaluatedKey')
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
"statusCode": response['ResponseMetadata']['HTTPStatusCode'],
|
|
||||||
"body": json.dumps(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
else:
|
|
||||||
return {
|
|
||||||
"statusCode": 404,
|
|
||||||
"body": json.dumps({
|
|
||||||
"error": "sorry this query did not produce any results",
|
|
||||||
"event": event
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
@ -2,6 +2,7 @@ import boto3
|
|||||||
import simplejson as json
|
import simplejson as json
|
||||||
import os
|
import os
|
||||||
from freqtrade.aws.tables import get_trade_table
|
from freqtrade.aws.tables import get_trade_table
|
||||||
|
from boto3.dynamodb.conditions import Key, Attr
|
||||||
|
|
||||||
|
|
||||||
def store(event, context):
|
def store(event, context):
|
||||||
@ -41,3 +42,70 @@ def submit(event, context):
|
|||||||
"statusCode": 200,
|
"statusCode": 200,
|
||||||
"body": json.dumps(result)
|
"body": json.dumps(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_aggregated_trades(event, context):
|
||||||
|
"""
|
||||||
|
returns the aggregated trades for the given key combination
|
||||||
|
:param event:
|
||||||
|
:param context:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert 'pathParameters' in event
|
||||||
|
assert 'user' in event['pathParameters']
|
||||||
|
assert 'name' in event['pathParameters']
|
||||||
|
assert 'ticker' in event['pathParameters']
|
||||||
|
assert 'days' in event['pathParameters']
|
||||||
|
|
||||||
|
|
||||||
|
def get_trades(event, context):
|
||||||
|
"""
|
||||||
|
this function returns all the known trades for a user, strategy and pair
|
||||||
|
:param event:
|
||||||
|
:param context:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert 'pathParameters' in event
|
||||||
|
assert 'user' in event['pathParameters']
|
||||||
|
assert 'name' in event['pathParameters']
|
||||||
|
assert 'stake' in event['pathParameters']
|
||||||
|
assert 'asset' in event['pathParameters']
|
||||||
|
|
||||||
|
table = get_trade_table()
|
||||||
|
|
||||||
|
response = table.query(
|
||||||
|
KeyConditionExpression=Key('id').eq(
|
||||||
|
"{}.{}:{}/{}".format(
|
||||||
|
event['pathParameters']['user'],
|
||||||
|
event['pathParameters']['name'],
|
||||||
|
event['pathParameters']['asset'].upper(),
|
||||||
|
event['pathParameters']['stake'].upper()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if "Items" in response and len(response['Items']) > 0:
|
||||||
|
|
||||||
|
# preparation for pagination
|
||||||
|
# TODO include in parameters an optional
|
||||||
|
# start key ExclusiveStartKey=response['LastEvaluatedKey']
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"result": response['Items'],
|
||||||
|
"paginationKey": response.get('LastEvaluatedKey')
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"statusCode": response['ResponseMetadata']['HTTPStatusCode'],
|
||||||
|
"body": json.dumps(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
"statusCode": 404,
|
||||||
|
"body": json.dumps({
|
||||||
|
"error": "sorry this query did not produce any results",
|
||||||
|
"event": event
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -1,13 +1,92 @@
|
|||||||
import os
|
|
||||||
from base64 import urlsafe_b64encode
|
from base64 import urlsafe_b64encode
|
||||||
|
|
||||||
import boto3
|
|
||||||
import pytest
|
import pytest
|
||||||
import simplejson as json
|
import simplejson as json
|
||||||
from mock import Mock
|
|
||||||
|
|
||||||
from freqtrade.aws.backtesting_lambda import backtest, cron
|
from freqtrade.aws.backtesting_lambda import backtest, cron
|
||||||
from freqtrade.aws.strategy import submit, get_trades
|
from freqtrade.aws.strategy import submit
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason="no way of currently testing this")
|
||||||
|
def test_backtest_remote(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 MyFancyTestStrategy(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": "MyFancyTestStrategy",
|
||||||
|
"content": urlsafe_b64encode(content.encode('utf-8')),
|
||||||
|
"public": False
|
||||||
|
}
|
||||||
|
|
||||||
|
# now we add an entry
|
||||||
|
submit({
|
||||||
|
"body": json.dumps(request)
|
||||||
|
}, {})
|
||||||
|
|
||||||
|
# build sns request
|
||||||
|
request = {
|
||||||
|
"user": "GCU4LW2XXZW3A3FM2XZJTEJHNWHTWDKY2DIJLCZJ5ULVZ4K7LZ7D23TG",
|
||||||
|
"name": "MyFancyTestStrategy",
|
||||||
|
"from": "20180401",
|
||||||
|
"till": "20180501",
|
||||||
|
"stake_currency": "usdt",
|
||||||
|
"assets": ["ltc"],
|
||||||
|
"local": False
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
assert backtest({
|
||||||
|
"Records": [
|
||||||
|
{
|
||||||
|
"Sns": {
|
||||||
|
"Subject": "backtesting",
|
||||||
|
"Message": json.dumps(request)
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}, {})['statusCode'] == 200
|
||||||
|
|
||||||
|
|
||||||
def test_backtest_time_frame(lambda_context):
|
def test_backtest_time_frame(lambda_context):
|
||||||
@ -60,10 +139,7 @@ class MyFancyTestStrategy(IStrategy):
|
|||||||
"description": "simple test strategy",
|
"description": "simple test strategy",
|
||||||
"name": "MyFancyTestStrategy",
|
"name": "MyFancyTestStrategy",
|
||||||
"content": urlsafe_b64encode(content.encode('utf-8')),
|
"content": urlsafe_b64encode(content.encode('utf-8')),
|
||||||
"public": False,
|
"public": False
|
||||||
"days": 1,
|
|
||||||
"local": True
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# now we add an entry
|
# now we add an entry
|
||||||
@ -78,7 +154,8 @@ class MyFancyTestStrategy(IStrategy):
|
|||||||
"from": "20180401",
|
"from": "20180401",
|
||||||
"till": "20180501",
|
"till": "20180501",
|
||||||
"stake_currency": "usdt",
|
"stake_currency": "usdt",
|
||||||
"assets": ["ltc"]
|
"assets": ["ltc"],
|
||||||
|
"local": True
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +236,7 @@ class MyFancyTestStrategy(IStrategy):
|
|||||||
"stake_currency": "usdt",
|
"stake_currency": "usdt",
|
||||||
"assets": ["ltc"],
|
"assets": ["ltc"],
|
||||||
"days": 2,
|
"days": 2,
|
||||||
|
"ticker": '15m',
|
||||||
"local": True
|
"local": True
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,6 +627,31 @@ def lambda_context():
|
|||||||
lamb = moto.mock_lambda()
|
lamb = moto.mock_lambda()
|
||||||
lamb.start()
|
lamb.start()
|
||||||
|
|
||||||
|
ecs = moto.mock_ecs()
|
||||||
|
ecs.start()
|
||||||
|
|
||||||
|
cluster = boto3.client('ecs')
|
||||||
|
cluster.create_cluster(clusterName='fargate')
|
||||||
|
|
||||||
|
cluster.register_task_definition(
|
||||||
|
containerDefinitions=[
|
||||||
|
{
|
||||||
|
'name': 'freqtrade-backtesting',
|
||||||
|
'command': [
|
||||||
|
'sleep',
|
||||||
|
'360',
|
||||||
|
],
|
||||||
|
'cpu': 10,
|
||||||
|
'essential': True,
|
||||||
|
'image': 'busybox',
|
||||||
|
'memory': 10,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
family='sleep360',
|
||||||
|
taskRoleArn='',
|
||||||
|
volumes=[
|
||||||
|
],
|
||||||
|
)
|
||||||
session = boto3.session.Session()
|
session = boto3.session.Session()
|
||||||
os.environ["strategyTable"] = "StrategyTable"
|
os.environ["strategyTable"] = "StrategyTable"
|
||||||
os.environ["tradeTable"] = "TradeTable"
|
os.environ["tradeTable"] = "TradeTable"
|
||||||
@ -649,3 +674,4 @@ def lambda_context():
|
|||||||
sns.stop()
|
sns.stop()
|
||||||
dynamo.stop()
|
dynamo.stop()
|
||||||
lamb.stop()
|
lamb.stop()
|
||||||
|
ecs.stop()
|
||||||
|
Loading…
Reference in New Issue
Block a user