Asynchronous BTgym environment setup.


  • This example shows base setup for asynchronious execution of multiply BTgym environment instances.
  • The main idea is to utilize separate BTgymDataFeedServer process to draw random episode data samples from one main dataset and pass it to every running environment.
  • This is quite a memory saver since every env. instance holds only small piece of data (single episode). Besides, sampling and dataset management is performed in it's own process.

In [1]:
import sys
sys.path.insert(0,'..')

import time
import multiprocessing

from btgym import BTgymEnv, BTgymDataset

In [2]:
class Worker(multiprocessing.Process):
    env = None
    
    def __init__(self, env_class, worker_id, num_episodes, env_config):
        super(Worker, self).__init__()
        self.env_class = env_class
        self.num_episodes = num_episodes
        self.env_config = env_config
        self.worker_id = worker_id
        
    def run(self):
        print('worker_{}: making environment...'.format(self.worker_id))
        self.env = self.env_class(**self.env_config)
        
        for episode in range(self.num_episodes):
            print('worker_{}: episode {} started.'.format(self.worker_id, episode))
            obs = self.env.reset()
            done = False
            while not done:
                # Just repeat `hold` action:
                obs, reward, done, info = self.env.step(0)
            # Get and report statistic:
            stat = self.env.get_stat() 
            print(
                'worker_{}: episode {} finished, {} steps made within {} seconds.'.
                  format(self.worker_id, stat['episode'], stat['length'], stat['runtime'])
            )   
        self.env.close()
        print('worker_{}: environmnt closed.'.format(self.worker_id))

In [5]:
# Provide data:
MyDataset = BTgymDataset(
    filename='../examples/data/DAT_ASCII_EURUSD_M1_2016.csv',
    start_weekdays=[0, 1, 2, 3, 4],
    episode_duration={'days': 1, 'hours': 23, 'minutes': 55},
    start_00=False,
    time_gap={'hours': 12},
)

# Setup:
num_workers = 8   # set it according to available CPU cores.
num_episodes = 2  # individual workplan.
base_port = 5000  # worker environment <--> BTgymServer communictaion, individual for every worker.
data_port = 4999  # BTgymServer <--> BTgymDataFeedServer communication, same for all workers.

workers = []

# Make data-master environment. In this example it will only serves as coordinator
# to start/stop data server, but can be exploited as full-time worker as well;
# just keep it runnung until others exit.
data_master = BTgymEnv(
    dataset=MyDataset,  # It is the only environment here for which dataset is required:
    port=5050,
    data_port=data_port,
    data_master=True,
    connect_timeout=10,  # set server connection timeout to 10 second (default is 60).
    verbose=0,
)

o = data_master.reset() # fake reset() to start data_server_process

# Make and launch workers in separate processes:
for i in range(num_workers):
    # Worker environment configuration:
    env_config=dict(
        port=base_port + i,
        data_port=data_port,
        data_master=False,  # This option forces environmnet to seek for datafeed provider server
                            # rather to use own dataset. Thus, no dataset is specified for this env.
        connect_timeout=10,
        verbose=0,
    )
    
    # Make:
    worker = Worker(
        env_class=BTgymEnv,
        worker_id=i,
        num_episodes=num_episodes,
        env_config=env_config,
    )
    
    # Launch:
    worker.daemon = False
    worker.start()
    workers.append(worker)
    # Artificial async, no need for this in real training:
    time.sleep(0.1)
    
# Wait everyone to finish:
for worker in workers:
    worker.join()
    print('...worker_{} has joined.'.format(worker.worker_id))
    
# shutdown data server :
data_master.close()

print('data_master: environment closed.')


[2017-12-18 19:25:28,687] Data_master `reset()` called prior to `reset_data()` with [possibly inconsistent] defaults.
worker_0: making environment...
worker_1: making environment...
worker_2: making environment...
worker_3: making environment...
worker_4: making environment...
worker_5: making environment...
worker_6: making environment...
worker_7: making environment...
worker_0: episode 0 started.
worker_1: episode 0 started.
worker_2: episode 0 started.
worker_3: episode 0 started.
worker_4: episode 0 started.
worker_5: episode 0 started.
worker_6: episode 0 started.
worker_7: episode 0 started.
worker_0: episode 0 finished, 2874 steps made within 0:00:04.970312 seconds.
worker_0: episode 1 started.
worker_1: episode 0 finished, 2874 steps made within 0:00:04.996122 seconds.
worker_1: episode 1 started.
worker_2: episode 0 finished, 2874 steps made within 0:00:05.133555 seconds.
worker_2: episode 1 started.
worker_3: episode 0 finished, 2874 steps made within 0:00:05.132922 seconds.
worker_3: episode 1 started.
worker_4: episode 0 finished, 2874 steps made within 0:00:05.430693 seconds.
worker_4: episode 1 started.
worker_6: episode 0 finished, 2874 steps made within 0:00:05.225778 seconds.
worker_6: episode 1 started.
worker_5: episode 0 finished, 2874 steps made within 0:00:05.371958 seconds.
worker_5: episode 1 started.
worker_7: episode 0 finished, 2874 steps made within 0:00:05.310113 seconds.
worker_7: episode 1 started.
worker_0: episode 1 finished, 2874 steps made within 0:00:04.669963 seconds.
worker_0: environmnt closed.
worker_1: episode 1 finished, 2874 steps made within 0:00:04.599960 seconds.
worker_1: environmnt closed.
worker_2: episode 1 finished, 2874 steps made within 0:00:04.532229 seconds.
...worker_0 has joined.
...worker_1 has joined.
worker_2: environmnt closed.
worker_3: episode 1 finished, 2874 steps made within 0:00:04.537144 seconds.
worker_3: environmnt closed.
...worker_2 has joined.
...worker_3 has joined.
worker_4: episode 1 finished, 2874 steps made within 0:00:04.346328 seconds.
worker_4: environmnt closed.
worker_5: episode 1 finished, 2874 steps made within 0:00:04.337170 seconds.
worker_5: environmnt closed.
worker_6: episode 1 finished, 2874 steps made within 0:00:04.462971 seconds.
worker_6: environmnt closed.
worker_7: episode 1 finished, 2874 steps made within 0:00:04.302940 seconds.
worker_7: environmnt closed.
...worker_4 has joined.
...worker_5 has joined.
...worker_6 has joined.
...worker_7 has joined.
data_master: environment closed.

Under the hood:


...for those who interested in what internal communications are going on:

  • just set verbose=2*:

*-DEBUG level - do not use that in real life due to data overflood.


In [7]:
MyDataset = BTgymDataset(
    filename='../examples/data/DAT_ASCII_EURUSD_M1_2016.csv',
    start_weekdays=[0, 1, 2, 3, 4],
    episode_duration={'days': 1, 'hours': 23, 'minutes': 55},
    start_00=False,
    time_gap={'hours': 12},
)

env1 = BTgymEnv(
    dataset=MyDataset,
    port=5050,
    data_port=4999,
    data_master=True,
    connect_timeout=5,
    verbose=2,
)

env2 = BTgymEnv(
    port=5052,
    data_port=4999,
    data_master=False,
    connect_timeout=5,
    verbose=2,
)

_1 = env1.reset()
_2 = env2.reset()

env2.close()
env1.close()


[2017-12-18 19:25:53,607] Custom Dataset class used.
[2017-12-18 19:25:53,608] Connecting data_server...
[2017-12-18 19:25:53,648] DataServer PID: 32495
[2017-12-18 19:25:54,352] Loaded 372678 records from <../examples/data/DAT_ASCII_EURUSD_M1_2016.csv>.
[2017-12-18 19:25:54,438] Data summary:
                open           high            low          close    volume
count  372678.000000  372678.000000  372678.000000  372678.000000  372678.0
mean        1.107109       1.107198       1.107019       1.107108       0.0
std         0.024843       0.024840       0.024847       0.024844       0.0
min         1.035250       1.035470       1.035220       1.035220       0.0
25%         1.092140       1.092230       1.092040       1.092140       0.0
50%         1.113530       1.113610       1.113450       1.113530       0.0
75%         1.124710       1.124780       1.124630       1.124710       0.0
max         1.161440       1.161600       1.160770       1.161450       0.0
[2017-12-18 19:25:54,441] If_sample: data_ready: False, fresh_sample: False
[2017-12-18 19:25:54,651] Pinging data_server at: tcp://127.0.0.1:4999 ...
[2017-12-18 19:25:54,653] DataServer received <{'ctrl': 'ping!'}>
[2017-12-18 19:25:54,655] DataServer sent: {'ctrl': 'waiting for control keys:  <_reset_data>, <_get_data>, <_get_info>, <_stop>.'}
[2017-12-18 19:25:54,656] Data_server seems ready with response: <{'ctrl': 'waiting for control keys:  <_reset_data>, <_get_data>, <_get_info>, <_stop>.'}>
[2017-12-18 19:25:54,656] If_sample: data_ready: False, fresh_sample: False
[2017-12-18 19:25:54,658] DataServer received <{'ctrl': '_get_info'}>
[2017-12-18 19:25:54,659] Sending info for #0.
[2017-12-18 19:25:54,661] If_sample: data_ready: False, fresh_sample: False
[2017-12-18 19:25:54,663] ...done.
[2017-12-18 19:25:54,664] Base Cerebro class used. Base Strategy class used.
[2017-12-18 19:25:54,673] Inferring `state_raw` high/low values form dataset: 1.035220 / 1.161600.
[2017-12-18 19:25:54,674] Obs. shape: OrderedDict([('raw_state', Box(4, 4))])
[2017-12-18 19:25:54,715] BTgymServer PID: 32500
[2017-12-18 19:25:54,719] BtgymServer: pinging data_server at: tcp://127.0.0.1:4999 ...
[2017-12-18 19:25:54,721] DataServer received <{'ctrl': 'ping!'}>
[2017-12-18 19:25:54,723] DataServer sent: {'ctrl': 'waiting for control keys:  <_reset_data>, <_get_data>, <_get_info>, <_stop>.'}
[2017-12-18 19:25:54,725] If_sample: data_ready: False, fresh_sample: False
[2017-12-18 19:25:54,725] BTgymServer: Data_server seems ready with response: <{'ctrl': 'waiting for control keys:  <_reset_data>, <_get_data>, <_get_info>, <_stop>.'}>
[2017-12-18 19:25:55,715] Server started, pinging tcp://127.0.0.1:5050 ...
[2017-12-18 19:25:55,717] Server Control mode: received <{'ctrl': 'ping!'}>
[2017-12-18 19:25:55,719] Server sent: {'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}
[2017-12-18 19:25:55,720] Server seems ready with response: <{'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}>
[2017-12-18 19:25:55,721] Environment is ready.
[2017-12-18 19:25:55,726] Connecting data_server...
[2017-12-18 19:25:55,727] Pinging data_server at: tcp://127.0.0.1:4999 ...
[2017-12-18 19:25:55,728] DataServer received <{'ctrl': 'ping!'}>
[2017-12-18 19:25:55,729] DataServer sent: {'ctrl': 'waiting for control keys:  <_reset_data>, <_get_data>, <_get_info>, <_stop>.'}
[2017-12-18 19:25:55,731] Data_server seems ready with response: <{'ctrl': 'waiting for control keys:  <_reset_data>, <_get_data>, <_get_info>, <_stop>.'}>
[2017-12-18 19:25:55,731] If_sample: data_ready: False, fresh_sample: False
[2017-12-18 19:25:55,733] DataServer received <{'ctrl': '_get_info'}>
[2017-12-18 19:25:55,734] Sending info for #0.
[2017-12-18 19:25:55,736] If_sample: data_ready: False, fresh_sample: False
[2017-12-18 19:25:55,737] ...done.
[2017-12-18 19:25:55,739] Base Cerebro class used. Base Strategy class used.
[2017-12-18 19:25:55,746] Inferring `state_raw` high/low values form dataset: 1.035220 / 1.161600.
[2017-12-18 19:25:55,747] Obs. shape: OrderedDict([('raw_state', Box(4, 4))])
[2017-12-18 19:25:55,791] BTgymServer PID: 32505
[2017-12-18 19:25:55,795] BtgymServer: pinging data_server at: tcp://127.0.0.1:4999 ...
[2017-12-18 19:25:55,797] DataServer received <{'ctrl': 'ping!'}>
[2017-12-18 19:25:55,799] DataServer sent: {'ctrl': 'waiting for control keys:  <_reset_data>, <_get_data>, <_get_info>, <_stop>.'}
[2017-12-18 19:25:55,801] If_sample: data_ready: False, fresh_sample: False
[2017-12-18 19:25:55,801] BTgymServer: Data_server seems ready with response: <{'ctrl': 'waiting for control keys:  <_reset_data>, <_get_data>, <_get_info>, <_stop>.'}>
[2017-12-18 19:25:56,790] Server started, pinging tcp://127.0.0.1:5052 ...
[2017-12-18 19:25:56,792] Server Control mode: received <{'ctrl': 'ping!'}>
[2017-12-18 19:25:56,794] Server sent: {'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}
[2017-12-18 19:25:56,796] Server seems ready with response: <{'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}>
[2017-12-18 19:25:56,797] Environment is ready.
[2017-12-18 19:25:56,799] DataServer received <{'ctrl': '_get_info'}>
[2017-12-18 19:25:56,800] Sending info for #0.
[2017-12-18 19:25:56,802] If_sample: data_ready: False, fresh_sample: False
[2017-12-18 19:25:56,804] Data_master `reset()` called prior to `reset_data()` with [possibly inconsistent] defaults.
[2017-12-18 19:25:56,805] Server Control mode: received <{'ctrl': '_done'}>
[2017-12-18 19:25:56,807] Server sent: {'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}
[2017-12-18 19:25:56,809] FORCE CONTROL MODE attempt: 1.
Response: {'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}
[2017-12-18 19:25:56,811] DataServer received <{'ctrl': '_reset_data', 'kwargs': {}}>
[2017-12-18 19:25:57,610] Loaded 372678 records from <../examples/data/DAT_ASCII_EURUSD_M1_2016.csv>.
[2017-12-18 19:25:57,622] DataServer sent: {'ctrl': 'Dataset has been reset with kwargs: {}'}
[2017-12-18 19:25:57,624] [_reset_data]: data_is_ready: True
[2017-12-18 19:25:57,626] Dataset seems ready with response: <{'ctrl': 'Dataset has been reset with kwargs: {}'}>
[2017-12-18 19:25:57,626] If_sample: data_ready: True, fresh_sample: False
[2017-12-18 19:25:57,627] Server Control mode: received <{'ctrl': '_done'}>
[2017-12-18 19:25:57,628] Maximum sample time duration set to: 1 day, 23:55:00.
[2017-12-18 19:25:57,630] Server sent: {'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}
[2017-12-18 19:25:57,630] Respective number of steps: 2875.
[2017-12-18 19:25:57,632] FORCE CONTROL MODE attempt: 1.
Response: {'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}
[2017-12-18 19:25:57,632] Maximum allowed data time gap set to: 12:00:00.
[2017-12-18 19:25:57,633] Server Control mode: received <{'ctrl': '_reset'}>

[2017-12-18 19:25:57,635] Starting episode.
[2017-12-18 19:25:57,636] Episode start: 2016-07-19 23:39:00, weekday: 1.
[2017-12-18 19:25:57,659] Episode duration: 1 day, 23:58:00.
[2017-12-18 19:25:57,661] Total episode time gap: 0:03:00.
[2017-12-18 19:25:57,663] Sample accepted.
[2017-12-18 19:25:57,665] Episode id: <_btgym_random_sample_2016-07-19 23:39:00>.
[2017-12-18 19:25:57,689] Got fresh: episode #0 metadata:
{'type': False, 'first_row': 204586, 'trial_num': False, 'sample_num': False}
[2017-12-18 19:25:57,693] DataServer received <{'ctrl': '_get_data'}>
[2017-12-18 19:25:57,707] Sending episode #0 data {'metadata': {'type': False, 'first_row': 204586, 'trial_num': False, 'sample_num': False}, 'datafeed': <backtrader.feeds.pandafeed.PandasDirectData object at 0x10ba48080>, 'episode_stat':               open         high          low        close  volume
count  2875.000000  2875.000000  2875.000000  2875.000000  2875.0
mean      1.101559     1.101645     1.101472     1.101559     0.0
std       0.001155     0.001159     0.001159     0.001155     0.0
min       1.098210     1.098430     1.097950     1.098150     0.0
25%       1.100840     1.100930     1.100750     1.100840     0.0
50%       1.101510     1.101590     1.101440     1.101520     0.0
75%       1.102380     1.102430     1.102320     1.102370     0.0
max       1.105650     1.105950     1.104860     1.105660     0.0, 'dataset_stat':                 open           high            low          close    volume
count  372678.000000  372678.000000  372678.000000  372678.000000  372678.0
mean        1.107109       1.107198       1.107019       1.107108       0.0
std         0.024843       0.024840       0.024847       0.024844       0.0
min         1.035250       1.035470       1.035220       1.035220       0.0
25%         1.092140       1.092230       1.092040       1.092140       0.0
50%         1.113530       1.113610       1.113450       1.113530       0.0
75%         1.124710       1.124780       1.124630       1.124710       0.0
max         1.161440       1.161600       1.160770       1.161450       0.0, 'local_step': 0}.
[2017-12-18 19:25:57,713] If_sample: data_ready: True, fresh_sample: False
[2017-12-18 19:25:57,717] Maximum sample time duration set to: 1 day, 23:55:00.
[2017-12-18 19:25:57,719] Data_server responded with datafeed in about 0.0793910026550293 seconds.
[2017-12-18 19:25:57,720] Respective number of steps: 2875.
[2017-12-18 19:25:57,722] Maximum allowed data time gap set to: 12:00:00.

[2017-12-18 19:25:57,729] Kwargs:
{'metadata': {'type': False, 'first_row': 204586, 'trial_num': False, 'sample_num': False}}

[2017-12-18 19:25:57,731] Episode start: 2016-02-28 20:29:00, weekday: 6.
[2017-12-18 19:25:57,735] Not a good day to start, resampling...
[2017-12-18 19:25:57,739] Episode start: 2016-10-20 19:25:00, weekday: 3.
[2017-12-18 19:25:57,747] Inner time embedding: 4
[2017-12-18 19:25:57,748] Episode duration: 4 days, 0:06:00.
[2017-12-18 19:25:57,751] COMM recieved: {'action': 'hold'}
[2017-12-18 19:25:57,751] Total episode time gap: 2 days, 0:11:00.
[2017-12-18 19:25:57,753] Duration too big, resampling...
[2017-12-18 19:25:57,755] Env response checker received:
({'raw_state': array([[ 1.10113,  1.10122,  1.10113,  1.10122],
       [ 1.10121,  1.10125,  1.10121,  1.10125],
       [ 1.10123,  1.10123,  1.10111,  1.10112],
       [ 1.10113,  1.10113,  1.1011 ,  1.10111]])}, 0.0, False, [{'step': 1, 'time': datetime.datetime(2016, 7, 19, 23, 42), 'action': 'hold', 'broker_message': '-', 'broker_cash': 10.0, 'broker_value': 10.0, 'drawdown': 0.0, 'max_drawdown': 0.0}])
as type: <class 'tuple'>

[2017-12-18 19:25:57,757] Episode start: 2016-09-18 18:16:00, weekday: 6.
[2017-12-18 19:25:57,757] Server Control mode: received <{'ctrl': '_done'}>
[2017-12-18 19:25:57,759] Not a good day to start, resampling...
[2017-12-18 19:25:57,759] Server sent: {'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}
[2017-12-18 19:25:57,761] FORCE CONTROL MODE attempt: 1.
Response: {'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}
[2017-12-18 19:25:57,761] Episode start: 2016-07-27 06:20:00, weekday: 2.
[2017-12-18 19:25:57,762] Server Control mode: received <{'ctrl': '_reset'}>
[2017-12-18 19:25:57,764] Starting episode.
[2017-12-18 19:25:57,765] Episode duration: 1 day, 23:56:00.
[2017-12-18 19:25:57,767] Total episode time gap: 0:01:00.
[2017-12-18 19:25:57,769] Sample accepted.
[2017-12-18 19:25:57,771] Episode id: <_btgym_random_sample_2016-07-27 06:20:00>.
[2017-12-18 19:25:57,791] Got fresh: episode #1 metadata:
{'type': False, 'first_row': 212157, 'trial_num': False, 'sample_num': False}
[2017-12-18 19:25:57,795] DataServer received <{'ctrl': '_get_data'}>
[2017-12-18 19:25:57,807] Sending episode #1 data {'metadata': {'type': False, 'first_row': 212157, 'trial_num': False, 'sample_num': False}, 'datafeed': <backtrader.feeds.pandafeed.PandasDirectData object at 0x10b9f1ba8>, 'episode_stat':               open         high          low        close  volume
count  2875.000000  2875.000000  2875.000000  2875.000000  2875.0
mean      1.106485     1.106570     1.106406     1.106488     0.0
std       0.003530     0.003522     0.003538     0.003529     0.0
min       1.096490     1.097390     1.096110     1.096520     0.0
25%       1.105855     1.105940     1.105810     1.105850     0.0
50%       1.107620     1.107670     1.107570     1.107620     0.0
75%       1.108700     1.108800     1.108610     1.108705     0.0
max       1.111660     1.111930     1.111190     1.111680     0.0, 'dataset_stat':                 open           high            low          close    volume
count  372678.000000  372678.000000  372678.000000  372678.000000  372678.0
mean        1.107109       1.107198       1.107019       1.107108       0.0
std         0.024843       0.024840       0.024847       0.024844       0.0
min         1.035250       1.035470       1.035220       1.035220       0.0
25%         1.092140       1.092230       1.092040       1.092140       0.0
50%         1.113530       1.113610       1.113450       1.113530       0.0
75%         1.124710       1.124780       1.124630       1.124710       0.0
max         1.161440       1.161600       1.160770       1.161450       0.0, 'local_step': 1}.
[2017-12-18 19:25:57,812] If_sample: data_ready: True, fresh_sample: False
[2017-12-18 19:25:57,817] Data_server responded with datafeed in about 0.04974794387817383 seconds.
[2017-12-18 19:25:57,820] Maximum sample time duration set to: 1 day, 23:55:00.
[2017-12-18 19:25:57,829] Respective number of steps: 2875.
[2017-12-18 19:25:57,831] Kwargs:
{'metadata': {'type': False, 'first_row': 212157, 'trial_num': False, 'sample_num': False}}
[2017-12-18 19:25:57,832] Maximum allowed data time gap set to: 12:00:00.


[2017-12-18 19:25:57,844] Episode start: 2016-09-21 06:39:00, weekday: 2.
[2017-12-18 19:25:57,850] Inner time embedding: 4
[2017-12-18 19:25:57,858] Episode duration: 1 day, 23:57:00.
[2017-12-18 19:25:57,860] COMM recieved: {'action': 'hold'}
[2017-12-18 19:25:57,865] Total episode time gap: 0:02:00.
[2017-12-18 19:25:57,868] Env response checker received:
({'raw_state': array([[ 1.10051,  1.10051,  1.10032,  1.10032],
       [ 1.10032,  1.10033,  1.10012,  1.10017],
       [ 1.10018,  1.1002 ,  1.10013,  1.10017],
       [ 1.10019,  1.10019,  1.1    ,  1.10001]])}, 0.0, False, [{'step': 1, 'time': datetime.datetime(2016, 7, 27, 6, 23), 'action': 'hold', 'broker_message': '-', 'broker_cash': 10.0, 'broker_value': 10.0, 'drawdown': 0.0, 'max_drawdown': 0.0}])
as type: <class 'tuple'>
[2017-12-18 19:25:57,867] Sample accepted.
[2017-12-18 19:25:57,870] Episode id: <_btgym_random_sample_2016-09-21 06:39:00>.
[2017-12-18 19:25:57,870] COMM recieved: {'ctrl': '_done'}
[2017-12-18 19:25:57,873] FORCE CONTROL MODE attempt: 1.
Response: _DONE SIGNAL RECEIVED
[2017-12-18 19:25:57,872] RunStop() invoked with -
[2017-12-18 19:25:57,895] Got fresh: episode #2 metadata:
{'type': False, 'first_row': 269586, 'trial_num': False, 'sample_num': False}
[2017-12-18 19:25:58,847] Episode elapsed time: 0:00:01.080951.
[2017-12-18 19:25:58,924] Server Control mode: received <{'ctrl': '_done'}>
[2017-12-18 19:25:58,926] Server sent: {'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}
[2017-12-18 19:25:58,928] FORCE CONTROL MODE attempt: 2.
Response: {'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}
[2017-12-18 19:25:58,929] Server Control mode: received <{'ctrl': '_stop'}>
[2017-12-18 19:25:58,930] Server is exiting.
[2017-12-18 19:25:58,932] Server is exiting. Exit code: None
[2017-12-18 19:25:58,933] Environment closed.
[2017-12-18 19:25:58,934] COMM recieved: {'ctrl': '_done'}
[2017-12-18 19:25:58,936] FORCE CONTROL MODE attempt: 1.
Response: _DONE SIGNAL RECEIVED
[2017-12-18 19:25:58,936] RunStop() invoked with -
[2017-12-18 19:25:59,719] Episode elapsed time: 0:00:02.081797.
[2017-12-18 19:25:59,809] Server Control mode: received <{'ctrl': '_done'}>
[2017-12-18 19:25:59,812] Server sent: {'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}
[2017-12-18 19:25:59,814] FORCE CONTROL MODE attempt: 2.
Response: {'ctrl': 'send control keys: <_reset>, <_getstat>, <_render>, <_stop>.'}
[2017-12-18 19:25:59,815] Server Control mode: received <{'ctrl': '_stop'}>
[2017-12-18 19:25:59,817] Server is exiting.
[2017-12-18 19:25:59,819] Server is exiting. Exit code: None
[2017-12-18 19:25:59,820] DataServer received <{'ctrl': '_stop'}>
[2017-12-18 19:25:59,822] {'ctrl': 'DataServer is exiting.'}
[2017-12-18 19:25:59,824] {'ctrl': 'DataServer is exiting.'} Exit code: None
[2017-12-18 19:25:59,825] Environment closed.

In [ ]:
dir(data_master)

In [ ]: