diff --git a/binarycpython/utils/grid.py b/binarycpython/utils/grid.py
index 992e9f97c69a88eb0dca5931b2f6b0257b499de5..7a18c516be4102223fa4293461e7005753ac3139 100644
--- a/binarycpython/utils/grid.py
+++ b/binarycpython/utils/grid.py
@@ -23,6 +23,8 @@ Tasks:
 import os
 import gc
 import sys
+from colorama import Fore,Back,Style,init as colorama_init
+
 import copy
 import json
 import time
@@ -93,7 +95,7 @@ from binarycpython.utils.distribution_functions import (
     raghavan2010_binary_fraction,
     Moe_di_Stefano_2017_multiplicity_fractions,
 )
-
+colorama_init()
 from binarycpython import _binary_c_bindings
 
 secs_per_day = 86400 # probably needs to go somewhere more sensible
@@ -154,6 +156,18 @@ class Population:
         # shared memory used for logging
         self.shared_memory = {}
 
+        # variable to test if we're running in a shell
+        if sys.stdin and sys.stdin.isatty():
+            self.in_shell = True
+        else:
+            self.in_shell = False
+
+        # ANSI colours: use them if in a shell
+        self.ANSI_colours = self._ANSI_colours()
+        if self.in_shell == False:
+            for c in self.ANSI_colours:
+                self.ANSI_colours[c] = ""
+
         # Set global (OS) process id
         self.grid_options["_main_pid"] = os.getpid()
 
@@ -255,7 +269,8 @@ class Population:
 
     def parse_cmdline(self) -> None:
         """
-        Function to handle settings values via the command line.
+        Function to handle settings values via the command line in the form x=y, w=z, etc.
+
         Best to be called after all the .set(..) lines, and just before the .evolve() is called
 
         If you input any known parameter (i.e. contained in grid_options, defaults/bse_options
@@ -266,21 +281,14 @@ class Population:
         can change to ints.
 
         The value of any new parameter (which will go to custom_options) will be a string.
-
-        Tasks:
-            - TODO: remove the need for --cmdline
         """
 
-        parser = argparse.ArgumentParser()
-        parser.add_argument(
-            "--cmdline",
-            help='Setting values via the commandline. Input like --cmdline "metallicity=0.02"',
-        )
-        args = parser.parse_args()
+        # get the cmd-line args in the form x=y
+        cmdline_args = sys.argv[1:]
 
         # How its set up now is that as input you need to give --cmdline "metallicity=0.002"
         # Its checked if this exists and handled accordingly.
-        if args.cmdline:
+        if cmdline_args:
             verbose_print(
                 "Found cmdline args. Parsing them now",
                 self.grid_options["verbosity"],
@@ -288,17 +296,12 @@ class Population:
             )
 
             # Grab the input and split them up, while accepting only non-empty entries
-            cmdline_args = args.cmdline
+            #cmdline_args = args
             self.grid_options["_commandline_input"] = cmdline_args
-            split_args = [
-                cmdline_arg
-                for cmdline_arg in cmdline_args.split(" ")
-                if not cmdline_arg == ""
-            ]
 
             # Make dict and fill it
             cmdline_dict = {}
-            for cmdline_arg in split_args:
+            for cmdline_arg in cmdline_args:
                 split = cmdline_arg.split("=")
                 parameter = split[0]
                 value = split[1]
@@ -852,15 +855,20 @@ class Population:
         # Reset population ID:
         self.grid_options["_population_id"] = uuid.uuid4().hex
 
+        # save number of stored log stats
+        self.shared_memory["n_saved_log_stats"] = multiprocessing.Value('i', 0)
+
         # set previous logging time
-        self.shared_memory["prev_log_time"] = multiprocessing.Value('d', time.time())
+        _t = time.time()
+
+        self.shared_memory["prev_log_time"] = multiprocessing.Array('d', [_t] * self.grid_options['n_logging_stats'])
 
         # set previous logging system number to 0
-        self.shared_memory["prev_log_system_number"] = multiprocessing.Value('i', 0)
+        self.shared_memory["prev_log_system_number"] = multiprocessing.Array('i', [0] * self.grid_options['n_logging_stats'])
 
         # array to store memory use per-thread
-        mem = mem_use()
-        self.shared_memory["memory_use_per_thread"] = multiprocessing.Array('d', [1.0 * mem] * self.grid_options["amt_cores"])
+        mem = 1.0 * mem_use()
+        self.shared_memory["memory_use_per_thread"] = multiprocessing.Array('d', [mem] * self.grid_options["amt_cores"])
 
     def clean(
         self
@@ -1333,7 +1341,7 @@ class Population:
 
         # variables for the statu bar prints
         start_grid_time = time.time()
-        next_log_time = self.shared_memory["prev_log_time"].value + self.grid_options["log_dt"]
+        next_log_time = self.shared_memory["prev_log_time"][0] + self.grid_options["log_dt"]
         next_mem_update_time = start_grid_time + self.grid_options["log_dt"]
 
         ############################################################
@@ -1406,7 +1414,7 @@ class Population:
                 next_mem_update_time = now + self.grid_options["log_dt"]
 
             # calculate the next logging time
-            next_log_time = self.shared_memory["prev_log_time"].value + self.grid_options["log_dt"]
+            next_log_time = self.shared_memory["prev_log_time"][0] + self.grid_options["log_dt"]
 
             # Check if we need to log info again
             # TODO: Check if we can put this functionality elsewhere
@@ -1420,8 +1428,23 @@ class Population:
 
                 # Set some values for next time
                 next_log_time = now + self.grid_options["log_dt"]
-                self.shared_memory["prev_log_time"].value = now
-                self.shared_memory["prev_log_system_number"].value = system_number
+
+                #print("PREV ",self.shared_memory["prev_log_time"])
+                #print("N LOG STATS",self.shared_memory["n_saved_log_stats"].value)
+
+                # shift the arrays
+                self.shared_memory["prev_log_time"][-(self.grid_options['n_logging_stats'] - 1):] = self.shared_memory["prev_log_time"][:(self.grid_options['n_logging_stats'] - 1)]
+                self.shared_memory["prev_log_system_number"][-(self.grid_options['n_logging_stats'] - 1):] = self.shared_memory["prev_log_system_number"][:(self.grid_options['n_logging_stats'] - 1)]
+
+                # set the current time and system number
+                self.shared_memory["prev_log_time"][0] = now
+                self.shared_memory["prev_log_system_number"][0] = system_number
+
+                # increase the number of stats
+                self.shared_memory["n_saved_log_stats"].value = min(self.shared_memory["n_saved_log_stats"].value+1,self.grid_options['n_logging_stats'])
+
+                #print("FIRST (0) ",self.shared_memory["prev_log_time"][0])
+                #print("LAST (",self.shared_memory["n_saved_log_stats"].value-1,")",self.shared_memory["prev_log_time"][self.shared_memory["n_saved_log_stats"].value-1])
 
             ###############
             # Log current system info
@@ -4285,8 +4308,17 @@ eccentricity3=0
         # calculate estimated time of arrive (eta and eta_secs), time per run (tpr)
         localtime = time.localtime(now)
 
-        dt = now - self.shared_memory["prev_log_time"].value
-        dn = system_number - self.shared_memory["prev_log_system_number"].value
+        # calculate stats
+        n = self.shared_memory["n_saved_log_stats"].value
+        if n < 2:
+            # simple 1-system calculation: inaccurate
+            # but best for small n
+            dt = now - self.shared_memory["prev_log_time"][0]
+            dn = system_number - self.shared_memory["prev_log_system_number"][0]
+        else:
+            # average over n_saved_log_stats
+            dt = self.shared_memory["prev_log_time"][0] - self.shared_memory["prev_log_time"][n-1]
+            dn = self.shared_memory["prev_log_system_number"][0] - self.shared_memory["prev_log_system_number"][n-1]
 
         eta, units, tpr, eta_secs = trem(
             dt,
@@ -4336,21 +4368,60 @@ eccentricity3=0
 
         # do the print
         verbose_print(
-            "{system_number}/{total_starcount}{modulo} {complete:5.1f}% complete {hours:02d}:{minutes:02d}:{seconds:02d} ETA={eta:7.1f}{units} tpr={tpr:2.2e} ETF={etf} mem:{mem_use:.1f}MB {system_string}".format(
+            "{opening_colour}{system_number}/{total_starcount}{modulo} {pc_colour}{pc_complete:5.1f}% complete {time_colour}{hours:02d}:{minutes:02d}:{seconds:02d} {ETA_colour}ETA={ETA:7.1f}{units} tpr={tpr:2.2e} {ETF_colour}ETF={ETF} {mem_use_colour}mem:{mem_use:.1f}MB {system_string_colour}{system_string}{closing_colour}".format(
+                opening_colour = self.ANSI_colours['reset'] + self.ANSI_colours['yellow on black'],
                 system_number = system_number,
                 total_starcount = self.grid_options["_total_starcount"],
-                complete=(100.0*system_number)/(1.0*self.grid_options["_total_starcount"]) if self.grid_options["_total_starcount"] else -1,
                 modulo = modulo,
+                pc_colour = self.ANSI_colours['blue on black'],
+                pc_complete=(100.0*system_number)/(1.0*self.grid_options["_total_starcount"]) if self.grid_options["_total_starcount"] else -1,
+                time_colour = self.ANSI_colours['green on black'],
                 hours = localtime.tm_hour,
                 minutes = localtime.tm_min,
                 seconds = localtime.tm_sec,
-                eta = eta,
+                ETA_colour = self.ANSI_colours['red on black'],
+                ETA = eta,
                 units = units,
                 tpr = tpr,
-                etf = etf,
+                ETF_colour = self.ANSI_colours['blue'],
+                ETF = etf,
+                mem_use_colour = self.ANSI_colours['magenta'],
                 mem_use = total_mem_use,
-                system_string=system_string
+                system_string_colour = self.ANSI_colours['yellow'],
+                system_string=system_string,
+                closing_colour = self.ANSI_colours['reset']
             ),
             self.grid_options["verbosity"],
             1
         )
+
+    def _ANSI_colours(self):
+        # ANSI colours dictionary
+        foreground_colours = {
+            'red':Fore.RED,
+            'yellow':Fore.YELLOW,
+            'blue':Fore.BLUE,
+            'cyan':Fore.CYAN,
+            'green':Fore.GREEN,
+            'magenta':Fore.MAGENTA,
+            'white':Fore.WHITE,
+            'black':Fore.BLACK,
+        }
+        background_colours = {
+            'red':Back.RED,
+            'yellow':Back.YELLOW,
+            'blue':Back.BLUE,
+            'cyan':Back.CYAN,
+            'green':Back.GREEN,
+            'magenta':Back.MAGENTA,
+            'white':Back.WHITE,
+            'black':Back.BLACK,
+        }
+        default_style = Style.BRIGHT
+        colours = {}
+        for c in foreground_colours:
+            colours[c] = default_style + foreground_colours[c]
+            for d in background_colours:
+                colours[c + ' on ' + d] = foreground_colours[c] + background_colours[d]
+        colours['reset'] = Style.RESET_ALL
+        return colours
diff --git a/binarycpython/utils/grid_options_defaults.py b/binarycpython/utils/grid_options_defaults.py
index 67c845abcfa93144b4b6f377da3bd10e1d3a80e9..140ea2e25e8d24597b3142b11da9d327ba28d07d 100644
--- a/binarycpython/utils/grid_options_defaults.py
+++ b/binarycpython/utils/grid_options_defaults.py
@@ -53,6 +53,7 @@ grid_options_defaults_dict = {
         temp_dir(), "binary_c_python.log"
     ),  # Set to None to not log to file. The directory will be created
     "log_dt" : 5, # time between vb=1 logging outputs
+    "n_logging_stats" : 50, # number of logging stats used to calculate time remaining (etc.) default = 50
     ##########################
     # binary_c files
     ##########################
diff --git a/requirements.txt b/requirements.txt
index e9d511142ece93bf128fa836e852761c6e265938..849cea1674d09ee33183259a71103715edd32b9c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,6 +5,7 @@ backcall==0.1.0
 certifi==2019.9.11
 chardet==3.0.4
 clang==6.0.0.2
+colorama==0.4.4
 cycler==0.10.0
 decorator==4.4.1
 dill==0.3.1.1
diff --git a/setup.py b/setup.py
index cac092170d2f73d37d656cf7e94031e81e8716c4..291e0793c129a196bad03462deeba44fbda05d79 100644
--- a/setup.py
+++ b/setup.py
@@ -29,7 +29,7 @@ def license():
 def check_version(installed_binary_c_version, required_binary_c_versions):
     """Function to check the installed version and compare it to the required version"""
     message = """
-    Something went wrong. Make sure that binary_c config exists. 
+    Something went wrong. Make sure that binary_c config exists.
     Possibly the binary_c version that is installed ({}) does not match the binary_c versions ({})
     that this release of the binary_c python module requires.
     """.format(
@@ -259,7 +259,8 @@ setup(
         "seaborn",
         "py_rinterpolate",
         "setproctitle",
-        "psutil"
+        "psutil",
+        "colorama"
     ],
     include_package_data=True,
     ext_modules=[BINARY_C_PYTHON_API_MODULE],  # binary_c must be loaded