Skip to content

Commit

Permalink
Upgraded Backtesting to v2 APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
guanidene committed Jul 26, 2020
1 parent 4384b15 commit 0eb79e8
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 47 deletions.
11 changes: 6 additions & 5 deletions pyalgotrading/algobulls/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import requests

from .exceptions import AlgoBullsAPIBaseException, AlgoBullsAPIUnauthorizedError, AlgoBullsAPIResourceNotFoundError, AlgoBullsAPIBadRequest, AlgoBullsAPIInternalServerErrorException
from .exceptions import AlgoBullsAPIBaseException, AlgoBullsAPIUnauthorizedError, AlgoBullsAPIInsufficientBalanceError, AlgoBullsAPIResourceNotFoundError, AlgoBullsAPIBadRequest, AlgoBullsAPIInternalServerErrorException
from ..constants import StrategyType, TradingType


Expand Down Expand Up @@ -65,6 +65,8 @@ def _send_request(self, method: str = 'get', endpoint: str = '', base_url: str =
raise AlgoBullsAPIBadRequest(f'Bad Request --> Method: {method} | URL: {url} | Response: {response_json}')
elif response.status_code == 401:
raise AlgoBullsAPIUnauthorizedError(f'Unauthorized Error --> Method: {method} | URL: {url} | Response: {response_json}')
elif response.status_code == 402:
raise AlgoBullsAPIInsufficientBalanceError(f'Insufficient Balance --> Method: {method} | URL: {url} | Response: {response_json}')
elif response.status_code == 404:
raise AlgoBullsAPIResourceNotFoundError(f'API Not Found --> Method: {method} | URL: {url} | Response: {response_json}')
elif response.status_code == 500:
Expand Down Expand Up @@ -183,7 +185,6 @@ def set_strategy_config(self, strategy_code: str, strategy_config: dict, trading
endpoint = f'v2/portfolio/strategy'
json_data = {'strategyId': strategy_code, 'tradingType': trading_type.value}
response1 = self._send_request(method='options', endpoint=endpoint, json_data=json_data)
print(response1)
key = response1.get('key')
# TODO: Check response to know if request was successful

Expand All @@ -209,11 +210,11 @@ def start_strategy_algotrading(self, key: str, trading_type: TradingType, broker
else:
raise NotImplementedError

json_data = {'method': 'update', 'key': key, 'record': {'status': 0}}
json_data = {'method': 'update', 'newVal': 1, 'key': key, 'record': {'status': 0}}
response = self._send_request(method='post', endpoint=endpoint, json_data=json_data)
return response

def stop_strategy_algotrading(self, strategy_code: str, trading_type: str, broker: str = '') -> dict:
def stop_strategy_algotrading(self, key: str, trading_type: str, broker: str = '') -> dict:
"""
Stop Backtesting / Paper Trading / Real Trading job for strategy with code strategy_code & return the job ID.
Expand All @@ -229,7 +230,7 @@ def stop_strategy_algotrading(self, strategy_code: str, trading_type: str, broke
else:
raise NotImplementedError

json_data = {'method': 'update', 'key': cstc_id, 'record': {'status': 0}}
json_data = {'method': 'update', 'newVal': 0, 'key': key, 'record': {'status': 2}}
response = self._send_request(method='post', endpoint=endpoint, json_data=json_data)
return response

Expand Down
36 changes: 18 additions & 18 deletions pyalgotrading/algobulls/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,18 +214,17 @@ def backtest(self, strategy_code, start_timestamp, end_timestamp, instrument_id,
assert (isinstance(strategy_code, str) is True), f'Argument strategy_code should be a string'
assert (isinstance(start_timestamp, dt) is True), f'Argument start_timestamp should be an instance of type datetime.datetime'
assert (isinstance(end_timestamp, dt) is True), f'Argument start_timestamp should be an instance of type datetime.datetime'
assert (isinstance(instrument_id, int) is True), f'Argument instrument_id should be a integer. You can find the right id using the \'get_instrument()\' method of AlgoBullsConnection class'
# assert (isinstance(instrument_id, int) is True), f'Argument instrument_id should be a integer. You can find the right id using the \'get_instrument()\' method of AlgoBullsConnection class'
assert (isinstance(strategy_parameters, dict) is True), f'Argument strategy_parameters should be a dict'
assert (isinstance(strategy_mode, StrategyMode) is True), f'Argument strategy_mode should be enum of type StrategyMode'
assert (isinstance(candle_interval, CandleInterval)), f'Argument candle_interval should be an enum of type CandleInterval'

# Setup config for Backtesting
strategy_config = {'trading_start_date': start_timestamp.date(), 'trading_start_time': start_timestamp.time(),
'trading_end_date': end_timestamp.date(), 'trading_end_time': end_timestamp.time(),
strategy_config = {'tradingTime': [start_timestamp.strftime('%d-%m-%Y %H:%M'), end_timestamp.strftime('%d-%m-%Y %H:%M')],
'instruments': [instrument_id],
'parameters': json.dumps(strategy_parameters),
'candle_interval': candle_interval.value,
'strategy_mode': strategy_mode}
'parameters': strategy_parameters,
'candle': candle_interval.value,
'strategyMode': strategy_mode.value}
print('Setting Strategy Config...', end=' ')
key, _ = self.api.set_strategy_config(strategy_code=strategy_code, strategy_config=strategy_config, trading_type=TradingType.BACKTESTING)
print('Success.')
Expand All @@ -235,10 +234,11 @@ def backtest(self, strategy_code, start_timestamp, end_timestamp, instrument_id,
response = self.api.start_strategy_algotrading(key=key, trading_type=TradingType.BACKTESTING)
print('Success.')

if response.get('success') is True:
return AlgoBullsJobSubmissionResponse(response['data'].upper())
else:
return AlgoBullsJobSubmissionResponse.ERROR, response
# print(response)
# if response.get('success') is True:
# return AlgoBullsJobSubmissionResponse(response['data'].upper())
# else:
# return AlgoBullsJobSubmissionResponse.ERROR, response

def get_backtesting_job_status(self, strategy_code):
"""
Expand Down Expand Up @@ -348,10 +348,10 @@ def papertrade(self, strategy_code, start_time, end_time, instrument_id, strateg
response = self.api.start_strategy_algotrading(key=key, trading_type=TradingType.PAPERTRADING)
print('Success.')

if response.get('success') is True:
return AlgoBullsJobSubmissionResponse(response['data'].upper())
else:
return AlgoBullsJobSubmissionResponse.ERROR, response
# if response.get('success') is True:
# return AlgoBullsJobSubmissionResponse(response['data'].upper())
# else:
# return AlgoBullsJobSubmissionResponse.ERROR, response

def get_papertrading_job_status(self, strategy_code):
"""
Expand Down Expand Up @@ -468,10 +468,10 @@ def realtrade(self, broker, strategy_code, start_time, end_time, instrument_id,
response = self.api.start_strategy_algotrading(key=key, trading_type=TradingType.REALTRADING, broker=broker.value)
print('Success.')

if response.get('success') is True:
return AlgoBullsJobSubmissionResponse(response['data'].upper())
else:
return AlgoBullsJobSubmissionResponse.ERROR, response
# if response.get('success') is True:
# return AlgoBullsJobSubmissionResponse(response['data'].upper())
# else:
# return AlgoBullsJobSubmissionResponse.ERROR, response

def get_realtrading_job_status(self, broker, strategy_code):
"""
Expand Down
7 changes: 7 additions & 0 deletions pyalgotrading/algobulls/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ class AlgoBullsAPIUnauthorizedError(AlgoBullsAPIBaseException):
pass


class AlgoBullsAPIInsufficientBalanceError(AlgoBullsAPIBaseException):
"""
Exception class for HTTP status code of 402 (Insufficient Balance)
"""
pass


class AlgoBullsAPIResourceNotFoundError(AlgoBullsAPIBaseException):
"""
Exception class for HTTP status code of 404 (Resource Not Found)
Expand Down
75 changes: 51 additions & 24 deletions pyalgotrading/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,32 +79,59 @@ class CandleInterval(Enum):
"""
A class of Candle Intervals with their Alternate names
"""
MINUTES_1 = 'minute'
MINUTES_3 = '3minutes'
MINUTES_5 = '5minutes'
MINUTES_10 = '10minutes'
MINUTES_15 = '15minutes'
MINUTES_30 = '30minutes'
MINUTES_60 = '60minutes'
HOURS_1 = '60minutes'
HOURS_24 = 'day'
DAYS_1 = 'day'
MINUTES_1 = 0
MINUTES_3 = 1
MINUTES_5 = 2
MINUTES_10 = 3
MINUTES_15 = 4
MINUTES_30 = 5
MINUTES_60 = 6
HOURS_1 = 6
HOURS_24 = 7
DAYS_1 = 7

# Alternative names
MINUTE_1 = 'minute'
MINUTE_3 = '3minutes'
MINUTE_5 = '5minutes'
MINUTE_10 = '10minutes'
MINUTE_15 = '15minutes'
MINUTE_30 = '30minutes'
MINUTE_60 = '60minutes'
HOUR_1 = '60minutes'
HOUR_24 = 'day'
DAY_1 = 'day'

MINUTE = 'minute'
HOUR = '60minutes'
DAY = 'day'
MINUTE_1 = 0
MINUTE_3 = 1
MINUTE_5 = 2
MINUTE_10 = 3
MINUTE_15 = 4
MINUTE_30 = 5
MINUTE_60 = 6
HOUR_1 = 6
HOUR_24 = 7
DAY_1 = 7

MINUTE = 0
HOUR = 6
DAY = 7

# MINUTES_1 = 'minute'
# MINUTES_3 = '3minutes'
# MINUTES_5 = '5minutes'
# MINUTES_10 = '10minutes'
# MINUTES_15 = '15minutes'
# MINUTES_30 = '30minutes'
# MINUTES_60 = '60minutes'
# HOURS_1 = '60minutes'
# HOURS_24 = 'day'
# DAYS_1 = 'day'
#
# # Alternative names
# MINUTE_1 = 'minute'
# MINUTE_3 = '3minutes'
# MINUTE_5 = '5minutes'
# MINUTE_10 = '10minutes'
# MINUTE_15 = '15minutes'
# MINUTE_30 = '30minutes'
# MINUTE_60 = '60minutes'
# HOUR_1 = '60minutes'
# HOUR_24 = 'day'
# DAY_1 = 'day'
#
# MINUTE = 'minute'
# HOUR = '60minutes'
# DAY = 'day'


class StrategyMode(Enum):
Expand Down

0 comments on commit 0eb79e8

Please sign in to comment.