Compare commits

..
52 Commits
Author SHA1 Message Date
avishaiw ca76d7271f DEV: encoding compatible to unix as well 2018-03-21 13:06:14 +02:00
AvishaiW d0abc8eac0 DEV: minor change in order to get log tail from server (WIP) 2018-03-14 09:40:45 +02:00
AvishaiW 4712db4f4f DEV: receiving a log from the cloud (WIP) 2018-03-12 10:53:53 +02:00
AvishaiW 8a812ea455 DEV: modified to the instance url (WIP) 2018-03-08 17:08:10 +02:00
AvishaiW e4933ee48e DEV: split client and server- added some docs (WIP) 2018-03-07 09:48:56 +02:00
AvishaiW b172f6b7b0 DEV: able to run locally through api- added backtesting as well (WIP) 2018-03-06 16:02:02 +02:00
AvishaiW 3335ef16a4 BLD: adding changes done in order to add the option to call the instance (WIP) 2018-03-05 22:19:46 +02:00
AvishaiW 71b246b9f1 DOC: added parameter to doc on exchange_bundle 2018-03-04 17:55:17 +02:00
AvishaiW aa520d5a8b STY: pep8 change in exchange_blotter 2018-03-04 17:24:22 +02:00
lenak25 e59f46dfd6 BLD: improve periods calculation 2018-03-04 13:47:08 +02:00
Victor Grau Serrat 5197ab6cc2 BUG: isolated Python3 depedency to the marketplace 2018-03-02 12:50:46 -07:00
Victor Grau Serrat d7b6cb8490 BUG: marketplace typo 2018-03-02 12:18:48 -07:00
Victor Grau Serrat fa0e9332bf MAINT: CLI info on marketplace cmds 2018-03-02 11:43:59 -07:00
VictorandGitHub d9d6a4e52d Merge pull request #257 from mattbornski/master
fix incompatibility with web3==4.0.0b11 from prior web3 versions
2018-03-02 11:38:52 -07:00
VictorandGitHub b4e5b699bd BUG: fix2 incompatibility with web3==4.0.0b11 2018-03-02 11:37:22 -07:00
VictorandGitHub f990ecf14d BUG: fix incompatibility with web3==4.0.0b11 2018-03-02 11:34:18 -07:00
lenak25 5d3a1c2f8b BLD: cosmetics 2018-03-02 00:39:28 +02:00
lenak25 3159ec7dc2 BLD: fix periods calculations and bundle unit-test 2018-03-02 00:36:13 +02:00
lenak25 8be0626fc9 BLD:refine unit-test 2018-03-01 18:16:57 +02:00
lenak25 868f17fd9d BLD:flake fixes 2018-03-01 16:39:42 +02:00
lenak25 b95cf465fc BLD:updating the forward fill to set volume to zero and others values to the previous close value 2018-03-01 16:09:09 +02:00
AvishaiW c4b10bae39 DOC: added- creating a virtual env for 3.6 2018-03-01 09:47:18 +02:00
AvishaiW 6c4f7afaea BUG: fixed removing files- check the path, not the file 2018-03-01 09:42:07 +02:00
Victor Grau Serrat b85219d5b4 MAINT: undoing last 2 unwanted commits 2018-02-28 18:06:36 -07:00
AvishaiW 082b342d02 Merge remote-tracking branch 'origin/develop' into cloud_conn 2018-03-01 01:11:46 +02:00
AvishaiW 37c1057ab6 BLD: added a cmd for running on the cloud (WIP) 2018-03-01 01:09:35 +02:00
Avishai WeingartenandGitHub 46e1a87a3d DOC: added troubleshooting for python3 2018-02-27 18:47:43 +02:00
Avishai WeingartenandGitHub cfafafb8fc BUG #252 fixed utc time and file erased 2018-02-27 09:47:02 +02:00
Matt Bornski 497212383a Python 3 returns bytes, the parsing functions are looking for strings 2018-02-26 15:44:32 -08:00
AvishaiW e5870ea60a BUG: fix #252 #253 and split state into paper and live 2018-02-26 09:21:00 +02:00
AvishaiW 8587fee0ce BUG: revert previous changes #249 2018-02-25 11:29:26 +02:00
Victor Grau Serrat 388535b09c BUG: reverts changed introduced in 00f232e2d7 2018-02-22 22:14:03 -07:00
Victor Grau Serrat 25e9f0f58f BUG: reverts changed introduced in 00f232e2d7 2018-02-22 22:09:51 -07:00
AvishaiW b4bd557273 BUG: fixes for issues #204 #237
-modified parameters for cancel_orders
-update portfolio after any change in
 the orders before sync
2018-02-23 00:38:51 +02:00
Victor Grau Serrat 2577b53518 MAINT: conda environment updates 2018-02-22 12:55:19 -07:00
Victor Grau Serrat 8fe3ab344e MAINT: conda environment updates 2018-02-22 12:54:36 -07:00
Victor bfd7e4b2dd Update python3.6-environment.yml 2018-02-22 12:54:36 -07:00
lenak25 50310576f9 BUG:fix an issue with wrong timestamps seen at tests.exchange.test_suites.test_suite_bundle.TestSuiteBundle#test_validate_bundles (which issue #230 uncovered) 2018-02-22 17:42:14 +02:00
lenak25 fea2ed104e BUG: fix issue #236: handle properly empty candles received from exchanges 2018-02-22 16:50:48 +02:00
embaral 127878413e DOC: added an option "catalyst live --help" to the documentation. 2018-02-22 14:45:14 +02:00
embaral 6a6ccf5595 Merge remote-tracking branch 'origin/develop' into develop 2018-02-22 14:37:46 +02:00
embaral d40585f56e DOC: added an option "catalyst live --help" to the documentation. 2018-02-22 14:34:00 +02:00
Victor Grau Serrat 4337abd60a DOC: linking example_algo to their sources 2018-02-21 15:51:34 -07:00
AvishaiW 92e0a7bb88 Merge branch 'develop' of https://github.com/enigmampc/catalyst into develop 2018-02-21 20:45:39 +02:00
AvishaiW 20f8a75f4a BUG: for issue #237, update positions before checking balances 2018-02-21 20:42:39 +02:00
Victor Grau Serrat ec5fdecf91 DOC: marketplace code examples 2018-02-16 11:50:16 -07:00
VictorandGitHub 9956b5462d Update python3.6-environment.yml 2018-02-14 09:27:53 -07:00
Victor Grau Serrat 46f34d64a0 MAINT: conda env for Python3 2018-02-13 12:06:06 -07:00
Victor Grau Serrat bc8bf6941d MAINT: contract+abi pointing to master, not develop 2018-02-09 16:08:22 -08:00
Frederic Fortier 49b6792399 Merge branch 'develop' 2018-02-09 12:01:57 -05:00
Victor Grau Serrat 3c4c6c3dfd DOC: small edits, eliminating sphinx warnings 2018-02-08 22:10:57 -07:00
Frederic Fortier 403d7f9c29 Merge branch 'develop' 2018-02-08 17:32:47 -05:00
15 changed files with 583 additions and 57 deletions
+192 -1
View File
@@ -506,6 +506,197 @@ def live(ctx,
return perf return perf
@main.command(name='serve')
@click.option(
'-f',
'--algofile',
default=None,
type=click.File('r'),
help='The file that contains the algorithm to run.',
)
@click.option(
'-t',
'--algotext',
help='The algorithm script to run.',
)
@click.option(
'-D',
'--define',
multiple=True,
help="Define a name to be bound in the namespace before executing"
" the algotext. For example '-Dname=value'. The value may be"
" any python expression. These are evaluated in order so they"
" may refer to previously defined names.",
)
@click.option(
'--data-frequency',
type=click.Choice({'daily', 'minute'}),
default='daily',
show_default=True,
help='The data frequency of the simulation.',
)
@click.option(
'--capital-base',
type=float,
show_default=True,
help='The starting capital for the simulation.',
)
@click.option(
'-b',
'--bundle',
default='poloniex',
metavar='BUNDLE-NAME',
show_default=True,
help='The data bundle to use for the simulation.',
)
@click.option(
'--bundle-timestamp',
type=Timestamp(),
default=pd.Timestamp.utcnow(),
show_default=False,
help='The date to lookup data on or before.\n'
'[default: <current-time>]'
)
@click.option(
'-s',
'--start',
type=Date(tz='utc', as_timestamp=True),
help='The start date of the simulation.',
)
@click.option(
'-e',
'--end',
type=Date(tz='utc', as_timestamp=True),
help='The end date of the simulation.',
)
@click.option(
'-o',
'--output',
default='-',
metavar='FILENAME',
show_default=True,
help="The location to write the perf data. If this is '-' the perf"
" will be written to stdout.",
)
@click.option(
'--print-algo/--no-print-algo',
is_flag=True,
default=False,
help='Print the algorithm to stdout.',
)
@ipython_only(click.option(
'--local-namespace/--no-local-namespace',
is_flag=True,
default=None,
help='Should the algorithm methods be resolved in the local namespace.'
))
@click.option(
'-x',
'--exchange-name',
help='The name of the targeted exchange.',
)
@click.option(
'-n',
'--algo-namespace',
help='A label assigned to the algorithm for data storage purposes.'
)
@click.option(
'-c',
'--base-currency',
help='The base currency used to calculate statistics '
'(e.g. usd, btc, eth).',
)
@click.pass_context
def run(ctx,
algofile,
algotext,
define,
data_frequency,
capital_base,
bundle,
bundle_timestamp,
start,
end,
output,
print_algo,
local_namespace,
exchange_name,
algo_namespace,
base_currency):
"""Run a backtest for the given algorithm on the server.
"""
if (algotext is not None) == (algofile is not None):
ctx.fail(
"must specify exactly one of '-f' / '--algofile' or"
" '-t' / '--algotext'",
)
# check that the start and end dates are passed correctly
if start is None and end is None:
# check both at the same time to avoid the case where a user
# does not pass either of these and then passes the first only
# to be told they need to pass the second argument also
ctx.fail(
"must specify dates with '-s' / '--start' and '-e' / '--end'"
" in backtest mode",
)
if start is None:
ctx.fail("must specify a start date with '-s' / '--start'"
" in backtest mode")
if end is None:
ctx.fail("must specify an end date with '-e' / '--end'"
" in backtest mode")
if exchange_name is None:
ctx.fail("must specify an exchange name '-x'")
if base_currency is None:
ctx.fail("must specify a base currency with '-c' in backtest mode")
if capital_base is None:
ctx.fail("must specify a capital base with '--capital-base'")
click.echo('Running in backtesting mode.', sys.stdout)
perf = run_server(
initialize=None,
handle_data=None,
before_trading_start=None,
analyze=None,
algofile=algofile,
algotext=algotext,
defines=define,
data_frequency=data_frequency,
capital_base=capital_base,
data=None,
bundle=bundle,
bundle_timestamp=bundle_timestamp,
start=start,
end=end,
output=output,
print_algo=print_algo,
local_namespace=local_namespace,
environ=os.environ,
live=False,
exchange=exchange_name,
algo_namespace=algo_namespace,
base_currency=base_currency,
analyze_live=None,
live_graph=False,
simulate_orders=True,
auth_aliases=None,
stats_output=None,
)
if output == '-':
click.echo(str(perf), sys.stdout)
elif output != os.devnull: # make the catalyst magic not write any data
perf.to_pickle(output)
return perf
@main.command(name='serve-live') @main.command(name='serve-live')
@click.option( @click.option(
'-f', '-f',
@@ -646,7 +837,7 @@ def serve_live(ctx,
handle_data=None, handle_data=None,
before_trading_start=None, before_trading_start=None,
analyze=None, analyze=None,
algofile=algofile, algofile=algofile,
algotext=algotext, algotext=algotext,
defines=define, defines=define,
data_frequency=None, data_frequency=None,
+5 -5
View File
@@ -27,20 +27,20 @@ AUTH_SERVER = 'https://data.enigma.co'
# TODO: switch to mainnet # TODO: switch to mainnet
ETH_REMOTE_NODE = 'https://ropsten.infura.io/' ETH_REMOTE_NODE = 'https://ropsten.infura.io/'
# TODO: move to MASTER branch on github
MARKETPLACE_CONTRACT = 'https://raw.githubusercontent.com/enigmampc/' \ MARKETPLACE_CONTRACT = 'https://raw.githubusercontent.com/enigmampc/' \
'catalyst/develop/catalyst/marketplace/' \ 'catalyst/master/catalyst/marketplace/' \
'contract_marketplace_address.txt' 'contract_marketplace_address.txt'
MARKETPLACE_CONTRACT_ABI = 'https://raw.githubusercontent.com/enigmampc/' \ MARKETPLACE_CONTRACT_ABI = 'https://raw.githubusercontent.com/enigmampc/' \
'catalyst/develop/catalyst/marketplace/' \ 'catalyst/master/catalyst/marketplace/' \
'contract_marketplace_abi.json' 'contract_marketplace_abi.json'
# TODO: switch to mainnet # TODO: switch to mainnet
ENIGMA_CONTRACT = 'https://raw.githubusercontent.com/enigmampc/catalyst/' \ ENIGMA_CONTRACT = 'https://raw.githubusercontent.com/enigmampc/catalyst/' \
'develop/catalyst/marketplace/' \ 'master/catalyst/marketplace/' \
'contract_enigma_address.txt' 'contract_enigma_address.txt'
ENIGMA_CONTRACT_ABI = 'https://raw.githubusercontent.com/enigmampc/' \ ENIGMA_CONTRACT_ABI = 'https://raw.githubusercontent.com/enigmampc/' \
'catalyst/develop/catalyst/marketplace/' \ 'catalyst/master/catalyst/marketplace/' \
'contract_enigma_abi.json' 'contract_enigma_abi.json'
+1 -1
View File
@@ -68,7 +68,7 @@ class TradingPairFeeSchedule(CommissionModel):
multiplier = maker \ multiplier = maker \
if ((order.amount > 0 and order.limit < transaction.price) if ((order.amount > 0 and order.limit < transaction.price)
or (order.amount < 0 and order.limit > transaction.price)) \ or (order.amount < 0 and order.limit > transaction.price)) \
and order.limit_reached else taker and order.limit_reached else taker
fee = cost * multiplier fee = cost * multiplier
return fee return fee
+1
View File
@@ -843,6 +843,7 @@ class ExchangeBundle:
field: str field: str
data_frequency: str data_frequency: str
algo_end_dt: pd.Timestamp algo_end_dt: pd.Timestamp
force_auto_ingest:
Returns Returns
------- -------
+27 -16
View File
@@ -716,25 +716,36 @@ def save_asset_data(folder, df, decimals=8):
) )
def get_candles_df(candles, field, freq, bar_count, end_dt, def forward_fill_df_if_needed(df, periods):
previous_value=None): df = df.reindex(periods)
# volume should always be 0 (if there were no trades in this interval)
df['volume'] = df['volume'].fillna(0.0)
# ie pull the last close into this close
df['close'] = df.fillna(method='pad')
# now copy the close that was pulled down from the last timestep
# into this row, across into o/h/l
df['open'] = df['open'].fillna(df['close'])
df['low'] = df['low'].fillna(df['close'])
df['high'] = df['high'].fillna(df['close'])
return df
def transform_candles_to_df(candles):
return pd.DataFrame(candles).set_index('last_traded')
def get_candles_df(candles, field, freq, bar_count, end_dt=None):
all_series = dict() all_series = dict()
for asset in candles: for asset in candles:
periods = pd.date_range(end=end_dt, periods=bar_count, freq=freq) asset_df = transform_candles_to_df(candles[asset])
rounded_end_dt = end_dt.floor(freq)
periods = pd.date_range(end=rounded_end_dt,
periods=bar_count,
freq=freq)
asset_df = forward_fill_df_if_needed(asset_df, periods)
dates = [candle['last_traded'] for candle in candles[asset]] all_series[asset] = pd.Series(asset_df[field])
values = [candle[field] for candle in candles[asset]]
series = pd.Series(values, index=dates)
"""
series = series.reindex(
periods,
method='ffill',
fill_value=previous_value,
)
series.sort_index(inplace=True)
"""
all_series[asset] = series
df = pd.DataFrame(all_series) df = pd.DataFrame(all_series)
df.dropna(inplace=True) df.dropna(inplace=True)
+24 -19
View File
@@ -23,7 +23,7 @@ from catalyst.exchange.utils.stats_utils import set_print_settings
from catalyst.marketplace.marketplace_errors import ( from catalyst.marketplace.marketplace_errors import (
MarketplacePubAddressEmpty, MarketplaceDatasetNotFound, MarketplacePubAddressEmpty, MarketplaceDatasetNotFound,
MarketplaceNoAddressMatch, MarketplaceHTTPRequest, MarketplaceNoAddressMatch, MarketplaceHTTPRequest,
MarketplaceNoCSVFiles) MarketplaceNoCSVFiles, MarketplaceRequiresPython3)
from catalyst.marketplace.utils.auth_utils import get_key_secret, \ from catalyst.marketplace.utils.auth_utils import get_key_secret, \
get_signed_headers get_signed_headers
from catalyst.marketplace.utils.bundle_utils import merge_bundles from catalyst.marketplace.utils.bundle_utils import merge_bundles
@@ -44,7 +44,10 @@ log = logbook.Logger('Marketplace', level=LOG_LEVEL)
class Marketplace: class Marketplace:
def __init__(self): def __init__(self):
global Web3 global Web3
from web3 import Web3, HTTPProvider try:
from web3 import Web3, HTTPProvider
except ImportError:
raise MarketplaceRequiresPython3()
self.addresses = get_user_pubaddr() self.addresses = get_user_pubaddr()
@@ -60,7 +63,8 @@ class Marketplace:
contract_url = urllib.urlopen(MARKETPLACE_CONTRACT) contract_url = urllib.urlopen(MARKETPLACE_CONTRACT)
self.mkt_contract_address = Web3.toChecksumAddress( self.mkt_contract_address = Web3.toChecksumAddress(
contract_url.readline().strip()) contract_url.readline().decode(
contract_url.info().get_content_charset()).strip())
abi_url = urllib.urlopen(MARKETPLACE_CONTRACT_ABI) abi_url = urllib.urlopen(MARKETPLACE_CONTRACT_ABI)
abi = json.load(abi_url) abi = json.load(abi_url)
@@ -73,7 +77,8 @@ class Marketplace:
contract_url = urllib.urlopen(ENIGMA_CONTRACT) contract_url = urllib.urlopen(ENIGMA_CONTRACT)
self.eng_contract_address = Web3.toChecksumAddress( self.eng_contract_address = Web3.toChecksumAddress(
contract_url.readline().strip()) contract_url.readline().decode(
contract_url.info().get_content_charset()).strip())
abi_url = urllib.urlopen(ENIGMA_CONTRACT_ABI) abi_url = urllib.urlopen(ENIGMA_CONTRACT_ABI)
abi = json.load(abi_url) abi = json.load(abi_url)
@@ -148,13 +153,13 @@ class Marketplace:
'Gas Price:\t\t[Accept the default value]\n' 'Gas Price:\t\t[Accept the default value]\n'
'Nonce:\t\t\t{nonce}\n' 'Nonce:\t\t\t{nonce}\n'
'Data:\t\t\t{data}\n'.format( 'Data:\t\t\t{data}\n'.format(
_from=from_address, _from=from_address,
to=tx['to'], to=tx['to'],
value=tx['value'], value=tx['value'],
gas=tx['gas'], gas=tx['gas'],
nonce=tx['nonce'], nonce=tx['nonce'],
data=tx['data'], ) data=tx['data'], )
) )
signed_tx = input('Copy and Paste the "Signed Transaction" ' signed_tx = input('Copy and Paste the "Signed Transaction" '
'field here:\n') 'field here:\n')
@@ -259,14 +264,14 @@ class Marketplace:
'buy: {} ENG. Get enough ENG to cover the costs of the ' 'buy: {} ENG. Get enough ENG to cover the costs of the '
'monthly\nsubscription for what you are trying to buy, ' 'monthly\nsubscription for what you are trying to buy, '
'and try again.'.format( 'and try again.'.format(
address, from_grains(balance), price)) address, from_grains(balance), price))
return return
while True: while True:
agree_pay = input('Please confirm that you agree to pay {} ENG ' agree_pay = input('Please confirm that you agree to pay {} ENG '
'for a monthly subscription to the dataset "{}" ' 'for a monthly subscription to the dataset "{}" '
'starting today. [default: Y] '.format( 'starting today. [default: Y] '.format(
price, dataset)) or 'y' price, dataset)) or 'y'
if agree_pay.lower() not in ('y', 'n'): if agree_pay.lower() not in ('y', 'n'):
print("Please answer Y or N.") print("Please answer Y or N.")
else: else:
@@ -369,7 +374,7 @@ class Marketplace:
'You can now ingest this dataset anytime during the ' 'You can now ingest this dataset anytime during the '
'next month by running the following command:\n' 'next month by running the following command:\n'
'catalyst marketplace ingest --dataset={}'.format( 'catalyst marketplace ingest --dataset={}'.format(
dataset, address, dataset)) dataset, address, dataset))
def process_temp_bundle(self, ds_name, path): def process_temp_bundle(self, ds_name, path):
""" """
@@ -426,10 +431,10 @@ class Marketplace:
print('Your subscription to dataset "{}" expired on {} UTC.' print('Your subscription to dataset "{}" expired on {} UTC.'
'Please renew your subscription by running:\n' 'Please renew your subscription by running:\n'
'catalyst marketplace subscribe --dataset={}'.format( 'catalyst marketplace subscribe --dataset={}'.format(
ds_name, ds_name,
pd.to_datetime(check_sub[4], unit='s', utc=True), pd.to_datetime(check_sub[4], unit='s', utc=True),
ds_name) ds_name)
) )
if 'key' in self.addresses[address_i]: if 'key' in self.addresses[address_i]:
key = self.addresses[address_i]['key'] key = self.addresses[address_i]['key']
@@ -621,7 +626,7 @@ class Marketplace:
) )
except Exception as e: except Exception as e:
print('Unable to subscribe to data source: {}'.format(e)) print('Unable to register the requested dataset: {}'.format(e))
return return
self.check_transaction(tx_hash) self.check_transaction(tx_hash)
+10 -1
View File
@@ -9,7 +9,8 @@ def silent_except_hook(exctype, excvalue, exctraceback):
MarketplaceNoAddressMatch, MarketplaceHTTPRequest, MarketplaceNoAddressMatch, MarketplaceHTTPRequest,
MarketplaceNoCSVFiles, MarketplaceContractDataNoMatch, MarketplaceNoCSVFiles, MarketplaceContractDataNoMatch,
MarketplaceSubscriptionExpired, MarketplaceJSONError, MarketplaceSubscriptionExpired, MarketplaceJSONError,
MarketplaceWalletNotSupported, MarketplaceEmptySignature]: MarketplaceWalletNotSupported, MarketplaceEmptySignature,
MarketplaceRequiresPython3]:
fn = traceback.extract_tb(exctraceback)[-1][0] fn = traceback.extract_tb(exctraceback)[-1][0]
ln = traceback.extract_tb(exctraceback)[-1][1] ln = traceback.extract_tb(exctraceback)[-1][1]
print("Error traceback: {1} (line {2})\n" print("Error traceback: {1} (line {2})\n"
@@ -86,3 +87,11 @@ class MarketplaceJSONError(ZiplineError):
'The configuration file {file} is malformed. Please correct ' 'The configuration file {file} is malformed. Please correct '
'the following error:\n{error}' 'the following error:\n{error}'
) )
class MarketplaceRequiresPython3(ZiplineError):
msg = (
'\nCatalyst requires Python3 to access the Enigma Data Marketplace.\n'
'If you want to use the Data Marketplace, you need to reinstall '
'Catalyst\nwith Python3. See the documentation website for additional '
'information.')
+32
View File
@@ -0,0 +1,32 @@
from catalyst.api import symbol
from catalyst.utils.run_algo import run_algorithm
coins = ['dash', 'btc', 'dash', 'etc', 'eth', 'ltc', 'nxt', 'rep', 'str', 'xmr', 'xrp', 'zec']
symbols = None
def initialize(context):
pass
def _handle_data(context, data):
global symbols
if symbols is None: symbols = [symbol(c + '_usdt') for c in coins]
print'getting history for: %s' % [s.symbol for s in symbols]
history = data.history(symbols,
['close', 'volume'],
bar_count=1, # EXCEPTION, Change to 2
frequency='5T')
#print 'history: %s' % history.shape
run_algorithm(initialize=initialize,
handle_data=_handle_data,
analyze=lambda _, results: True,
exchange_name='poloniex',
base_currency='usdt',
algo_namespace='issue-236',
live=True,
data_frequency='minute',
capital_base=3000,
simulate_orders=True)
+103
View File
@@ -0,0 +1,103 @@
#!flask/bin/python
import base64
import requests
import pandas as pd
import json
def convert_date(date):
"""
when transferring dates by json,
converts it to str
:param date:
:return: str(date)
"""
if isinstance(date, pd.Timestamp):
return date.__str__()
def run_server(
initialize,
handle_data,
before_trading_start,
analyze,
algofile,
algotext,
defines,
data_frequency,
capital_base,
data,
bundle,
bundle_timestamp,
start,
end,
output,
print_algo,
local_namespace,
environ,
live,
exchange,
algo_namespace,
base_currency,
live_graph,
analyze_live,
simulate_orders,
auth_aliases,
stats_output,
):
# address to send
url = 'http://sandbox.enigma.co/api/catalyst/serve'
# url = 'http://127.0.0.1:5000/api/catalyst/serve'
# argument preparation - encode the file for transfer
if algotext:
algotext = base64.b64encode(algotext)
else:
algotext = base64.b64encode(bytes(algofile.read(), 'utf-8')).decode('utf-8')
algofile = None
json_file = {'arguments': {
'initialize': initialize,
'handle_data': handle_data,
'before_trading_start': before_trading_start,
'analyze': analyze,
'algotext': algotext,
'defines': defines,
'data_frequency': data_frequency,
'capital_base': capital_base,
'data': data,
'bundle': bundle,
'bundle_timestamp': bundle_timestamp,
'start': start,
'end': end,
'local_namespace': local_namespace,
'environ': None,
'analyze_live': analyze_live,
'stats_output': stats_output,
'algofile': algofile,
'output': output,
'print_algo': print_algo,
'live': live,
'exchange': exchange,
'algo_namespace': algo_namespace,
'base_currency': base_currency,
'live_graph': live_graph,
'simulate_orders': simulate_orders,
'auth_aliases': auth_aliases,
}}
response = requests.post(url,
json=json.dumps(
json_file,
default=convert_date
)
)
if response.status_code == 500:
raise Exception("issues with cloud connections, "
"unable to run catalyst on the cloud")
received_data = response.json()
cloud_log_tail = base64.b64decode(received_data["log"])
print(cloud_log_tail)
+1 -2
View File
@@ -143,8 +143,7 @@ with the following steps:
.. code-block:: bash .. code-block:: bash
conda create --name catalyst python=3.6 scipy zlib conda create --name catalyst python=2.7 scipy zlib
3. Activate the environment: 3. Activate the environment:
+3 -1
View File
@@ -23,7 +23,9 @@ dependencies:
- bottleneck==1.2.1 - bottleneck==1.2.1
- chardet==3.0.4 - chardet==3.0.4
- ccxt==1.10.1094 - ccxt==1.10.1094
- web3==4.0.0b7 # The Enigma Data Marketplace requires Python3 because it depends on
# web3, which requires Python3, as building its dependencies breaks in Python2
# - web3==4.0.0b7
- requests-toolbelt==0.8.0 - requests-toolbelt==0.8.0
- click==6.7 - click==6.7
- contextlib2==0.5.5 - contextlib2==0.5.5
+1 -1
View File
@@ -84,5 +84,5 @@ tables==3.3.0
ccxt==1.10.1094 ccxt==1.10.1094
boto3==1.4.8 boto3==1.4.8
redo==1.6 redo==1.6
web3==4.0.0b7 web3==4.0.0b11; python_version > '3.4'
requests-toolbelt==0.8.0 requests-toolbelt==0.8.0
-2
View File
@@ -1,2 +0,0 @@
web3==4.0.0b7
requests-toolbelt==0.8.0
+175
View File
@@ -0,0 +1,175 @@
from catalyst.exchange.utils.exchange_utils import transform_candles_to_df, \
forward_fill_df_if_needed, get_candles_df
from catalyst.testing.fixtures import WithLogger, ZiplineTestCase
from datetime import timedelta
from pandas import Timestamp, DataFrame, concat
import numpy as np
class TestExchangeUtils(WithLogger, ZiplineTestCase):
@classmethod
def get_specific_field_from_df(cls, df, field, asset):
new_df = DataFrame(df[field])
new_df.columns = [asset]
new_df.index.name = None
return new_df
@classmethod
def verify_forward_fill_df_if_needed(cls, candles, periods, expected_df):
observed_df = forward_fill_df_if_needed(
transform_candles_to_df(candles),
periods)
assert (expected_df.equals(observed_df))
@classmethod
def verify_get_candles_df(cls, assets, candles, end_fixed_dt,
expected_df, check_next_candle=False):
# run on all the fields
for field in ['volume', 'open', 'close', 'high', 'low']:
field_dt = cls.get_specific_field_from_df(expected_df,
field,
assets[0])
# run on several timestamps
for delta in range(5):
end_dt = end_fixed_dt + timedelta(minutes=delta)
assert (field_dt.equals(get_candles_df({assets[0]: candles},
field, '5T', 3,
end_dt=end_dt)))
field_dt_a1 = cls.get_specific_field_from_df(expected_df,
field,
assets[0])
field_dt_a2 = cls.get_specific_field_from_df(expected_df,
field,
assets[1])
observed_df = get_candles_df({assets[0]: candles,
assets[1]: candles},
field, '5T', 3,
end_dt=end_dt)
assert (observed_df.equals(concat([field_dt_a1, field_dt_a2],
axis=1)))
if check_next_candle:
# one candle forward
end_dt = end_fixed_dt + timedelta(minutes=6)
observed_df = get_candles_df({assets[0]: candles,
assets[1]: candles},
field, '5T', 3,
end_dt=end_dt)
assert (not observed_df.equals(concat([field_dt_a1,
field_dt_a2],
axis=1)))
assert (concat([field_dt_a1, field_dt_a2],
axis=1)[1:].equals(observed_df[:-1]))
def test_get_candles_df(self):
assets = ['btc_usdt', 'eth_usdt']
# test forward fill in the end
candles = [{'high': 595, 'volume': 10, 'low': 594,
'close': 595, 'open': 594,
'last_traded': Timestamp('2018-03-01 09:45:00+0000',
tz='UTC')
},
{'high': 594, 'volume': 108, 'low': 592,
'close': 593, 'open': 592,
'last_traded': Timestamp('2018-03-01 09:50:00+0000',
tz='UTC')
}]
expected = [{'high': 595.0, 'volume': 10.0, 'low': 594.0,
'close': 595.0, 'open': 594.0,
'last_traded': Timestamp('2018-03-01 09:45:00+0000',
tz='UTC')
},
{'high': 594.0, 'volume': 108.0, 'low': 592.0,
'close': 593.0, 'open': 592.0,
'last_traded': Timestamp('2018-03-01 09:50:00+0000',
tz='UTC')
},
{'high': 593.0, 'volume': 0.0, 'low': 593.0,
'close': 593.0, 'open': 593.0,
'last_traded': Timestamp('2018-03-01 09:55:00+0000',
tz='UTC')
}]
periods = [Timestamp('2018-03-01 09:45:00+0000', tz='UTC'),
Timestamp('2018-03-01 09:50:00+0000', tz='UTC'),
Timestamp('2018-03-01 09:55:00+0000', tz='UTC')]
expected_df = transform_candles_to_df(expected)
self.verify_forward_fill_df_if_needed(candles, periods,
expected_df)
self.verify_get_candles_df(assets, candles, periods[2],
expected_df, True)
# test forward fill in the middle
candles = [{'high': 595, 'volume': 10, 'low': 594,
'close': 595, 'open': 594,
'last_traded': Timestamp('2018-03-01 09:45:00+0000',
tz='UTC')
},
{'high': 594, 'volume': 108, 'low': 592,
'close': 593, 'open': 592,
'last_traded': Timestamp('2018-03-01 09:55:00+0000',
tz='UTC')
}]
expected = [{'high': 595.0, 'volume': 10.0, 'low': 594.0,
'close': 595.0, 'open': 594.0,
'last_traded': Timestamp('2018-03-01 09:45:00+0000',
tz='UTC')
},
{'high': 595.0, 'volume': 0.0, 'low': 595.0,
'close': 595.0, 'open': 595.0,
'last_traded': Timestamp('2018-03-01 09:50:00+0000',
tz='UTC')
},
{'high': 594.0, 'volume': 108.0, 'low': 592.0,
'close': 593.0, 'open': 592.0,
'last_traded': Timestamp('2018-03-01 09:55:00+0000',
tz='UTC')
}]
expected_df = transform_candles_to_df(expected)
self.verify_forward_fill_df_if_needed(candles, periods, expected_df)
self.verify_get_candles_df(assets, candles, periods[2], expected_df)
# test "forward fill" at the beginning
candles = [{'high': 595, 'volume': 10, 'low': 594,
'close': 595, 'open': 594,
'last_traded': Timestamp('2018-03-01 09:50:00+0000',
tz='UTC')
},
{'high': 594, 'volume': 108, 'low': 592,
'close': 593, 'open': 592,
'last_traded': Timestamp('2018-03-01 09:55:00+0000',
tz='UTC')
}]
expected = [{'high': np.NaN, 'volume': 0.0, 'low': np.NaN,
'close': np.NaN, 'open': np.NaN,
'last_traded': Timestamp('2018-03-01 09:45:00+0000',
tz='UTC')
},
{'high': 595, 'volume': 10, 'low': 594,
'close': 595, 'open': 594,
'last_traded': Timestamp('2018-03-01 09:50:00+0000',
tz='UTC')
},
{'high': 594, 'volume': 108, 'low': 592,
'close': 593, 'open': 592,
'last_traded': Timestamp('2018-03-01 09:55:00+0000',
tz='UTC')
}]
expected_df = transform_candles_to_df(expected)
self.verify_forward_fill_df_if_needed(candles, periods, expected_df)
# Not the same due to dropna - commenting out for now
# self.verify_get_candles_df(assets, candles, periods[2], expected_df)
@@ -107,14 +107,14 @@ class TestSuiteBundle:
print('saved {} test results: {}'.format(end_dt, folder)) print('saved {} test results: {}'.format(end_dt, folder))
assert_frame_equal( assert_frame_equal(
right=data['bundle'], right=data['bundle'][:-1],
left=data['exchange'], left=data['exchange'][:-1],
check_less_precise=1, check_less_precise=1,
) )
try: try:
assert_frame_equal( assert_frame_equal(
right=data['bundle'], right=data['bundle'][:-1],
left=data['exchange'], left=data['exchange'][:-1],
check_less_precise=min([a.decimals for a in assets]), check_less_precise=min([a.decimals for a in assets]),
) )
except Exception as e: except Exception as e: