""" MarketTick Data Resample Script Needs Python3 to run: https://www.python.org/downloads/ Runs on Windows, Linux, Mac Usage: "python MarketTick_Resample.txt" in a command shell """ def print_header(): header = r""" __ __ _ _ _____ _ _ | \/ | __ _ _ __| | _____| ||_ _(_) ___| | __ | |\/| |/ _` | '__| |/ / _ \ __|| | | |/ __| |/ / | | | | (_| | | | < __/ |_ | | | | (__| < |_| |_|\__,_|_| |_|\_\___|\__||_| |_|\___|_|\_\ Data Resample Script V3.2 ©2025 MarketTick.net -------------------------------------------------- ✅ Add-on for Level1+2 and Candlestick resample found -> Resample option enabled!""" usage_info = r"""-------------------------------------------------- This script converts/resamples/filters tick data from MarketTick to different formats or timeframes. 1. Unzip all the CSV files you want to convert into a single folder 2. Contact info@markettick.net if you need a specific Add-on 3. Run this script and specify the full path to the folder with the unzipped CSV files 4. Select the desired option """ print(header) MarketTick_Resample_NT.printStatus() #NinjaTrader MarketTick_Resample_MT5.printStatus() #MetaTrader 5 MarketTick_Resample_SC.printStatus() #Sierra Chart MarketTick_Resample_MC.printStatus() #MultiCharts MarketTick_Resample_BT.printStatus() #Backtrader print(usage_info) # MAIN Code starts here import os if os.path.exists("MarketTick_Resample_NT.txt") and not os.path.exists("MarketTick_Resample_NT.py"): os.rename("MarketTick_Resample_NT.txt", "MarketTick_Resample_NT.py") import datetime as dt from zoneinfo import ZoneInfo, ZoneInfoNotFoundError try: import MarketTick_Resample_NT except ImportError: class ResampleNTFallback: def isPresent(self): return False def printStatus(self): print("❌ Add-on for NinjaTrader conversion not found -> Conversion option disabled!") MarketTick_Resample_NT = ResampleNTFallback() try: import MarketTick_Resample_MT5 except ImportError: class ResampleMT5Fallback: def isPresent(self): return False def printStatus(self): print("❌ Add-on for MetaTrader 5 conversion not found -> Conversion option disabled!") MarketTick_Resample_MT5 = ResampleMT5Fallback() try: import MarketTick_Resample_SC except ImportError: class ResampleSCFallback: def isPresent(self): return False def printStatus(self): print("❌ Add-on for Sierra Chart conversion not found -> Conversion option disabled!") MarketTick_Resample_SC = ResampleSCFallback() try: import MarketTick_Resample_MC except ImportError: class ResampleMCFallback: def isPresent(self): return False def printStatus(self): print("❌ Add-on for MultiCharts conversion not found -> Conversion option disabled!") MarketTick_Resample_MC = ResampleMCFallback() try: import MarketTick_Resample_BT except ImportError: class ResampleBTFallback: def isPresent(self): return False def printStatus(self): print("❌ Add-on for Backtrader conversion not found -> Conversion option disabled!") MarketTick_Resample_BT = ResampleBTFallback() def determine_type(file_path): """ Determine file type in order T2, T1, C1. """ detected_type = "C1" # default with open(file_path, encoding='utf-8') as f: for line in f: line = line.strip() if not line: continue columns = line.split(';') # Check for T2: if column 2 is "2" anywhere if len(columns) > 1 and columns[1] == "2" and len(columns[0]) != 14: return "T2" with open(file_path, encoding='utf-8') as f: for line in f: line = line.strip() if not line: continue columns = line.split(';') if len(columns) == 0: continue first_col = columns[0] if len(first_col) != 14: return "T1" return "C1" def get_conversion_options(current_type): """ Return available conversion options depending on detected type. """ if current_type == "T2": options = { "1": ("T1", "Resample Level2 Tick Data to Level1 Tick Data"), "2": ("T1TRADE", "Resample Level2 Tick Data to Level1 Tick Data ONLY TRADEs"), "3": ("C", "Resample Level2 Tick Data to OHLCV Candlesticks"), "4": ("T2SPLIT", "Split Level2 Tick Data into seperate Level1 and Level2 files"), "5": ("TZ", "Convert UTC time zone to another time zone") } if MarketTick_Resample_NT.isPresent(): options[str(len(options)+1)] = ("AddOn_NT", "Convert Level2 Tick Data to NinjaTrader import format (only Level1 Tick import possible in NinjaTrader)") if MarketTick_Resample_MT5.isPresent(): options[str(len(options)+1)] = ("AddOn_MT5", "Convert Level2 Tick Data to MetaTrader 5 import format") if MarketTick_Resample_SC.isPresent(): options[str(len(options)+1)] = ("AddOn_SC", "Convert Level2 Tick Data to Sierra Chart import format") if MarketTick_Resample_MC.isPresent(): options[str(len(options)+1)] = ("AddOn_MC", "Convert Level2 Tick Data to MultiCharts import format") if MarketTick_Resample_BT.isPresent(): options[str(len(options)+1)] = ("AddOn_BT", "Convert Level2 Tick Data to Backtrader import format") elif current_type == "T1": options = { "1": ("T1TRADE", "Resample Level1 Tick Data to Level1 Tick Data ONLY TRADEs"), "2": ("C", "Resample Level1 Tick Data to OHLCV Candlesticks"), "3": ("TZ", "Convert UTC time zone to another time zone") } if MarketTick_Resample_NT.isPresent(): options[str(len(options)+1)] = ("AddOn_NT", "Convert Level1 Tick Data to NinjaTrader import format") if MarketTick_Resample_MT5.isPresent(): options[str(len(options)+1)] = ("AddOn_MT5", "Convert Level1 Tick Data to MetaTrader 5 import format") if MarketTick_Resample_SC.isPresent(): options[str(len(options)+1)] = ("AddOn_SC", "Convert Level1 Tick Data to Sierra Chart import format") if MarketTick_Resample_MC.isPresent(): options[str(len(options)+1)] = ("AddOn_MC", "Convert Level1 Tick Data to MultiCharts import format") if MarketTick_Resample_BT.isPresent(): options[str(len(options)+1)] = ("AddOn_BT", "Convert Level1 Tick Data to Backtrader import format") elif current_type == "C1": options = { # "2": ("C", "Resample OHLCV Candlesticks Data to other timeframe"), "1": ("TZ", "Convert UTC time zone to another time zone") } else: options = {} if not options: print("No conversion possible or necessary. Program ends.") return {} print("Choose the target type for conversion:") for key, (typ, desc) in options.items(): print(f"{key}. {desc}") print(f"") while True: choice = input("Please enter the number of the desired target type: ").strip() if choice in options: break else: print(f"Invalid choice. Please select one of: {', '.join(options.keys())}") print(f"") return options[choice][0] def get_conversion_steps_C(): """ Specifies Candlistick interval. """ options = { "1s": (1, "Resample to 1second OHLCV Candlesticks"), "5s": (5, "Resample to 5second OHLCV Candlesticks"), "10s": (10, "Resample to 10second OHLCV Candlesticks"), "15s": (15, "Resample to 15second OHLCV Candlesticks"), "30s": (30, "Resample to 30second OHLCV Candlesticks"), "1m": (60, "Resample to 1minute OHLCV Candlesticks"), "5m": (300, "Resample to 5minute OHLCV Candlesticks"), "10m": (600, "Resample to 10minute OHLCV Candlesticks"), "15m": (900, "Resample to 15minute OHLCV Candlesticks"), "30m": (1800, "Resample to 30minute OHLCV Candlesticks"), "1h": (3600, "Resample to 1hour OHLCV Candlesticks"), "2h": (7200, "Resample to 2hour OHLCV Candlesticks"), "3h": (10800, "Resample to 3hour OHLCV Candlesticks"), "4h": (14400, "Resample to 4hour OHLCV Candlesticks"), "1d": (86400, "Resample to 1day OHLCV Candlesticks") } print("Choose the target timeframe for Candlestick conversion:") for key, (typ, desc) in options.items(): print(f"{key}. {desc}") print(f"") while True: choice = input("Please enter the desired target timeframe: ").strip() if choice in options: break else: print(f"Invalid choice. Please select one of: {', '.join(options.keys())}") print(f"") print(f"") return (choice, options[choice][0]) def get_conversion_timezone(): """ Specifies new timezone. """ options = { "1": ("America/New_York", "NYSE, Nasdaq"), "2": ("America/Chicago", "CME"), "3": ("America/Toronto", "TSX"), "4": ("America/Sao_Paulo", "B3"), "5": ("Europe/London", "LSE"), "6": ("Europe/Berlin", "Xetra, Eurex, SIX, Euronext"), "7": ("Europe/Moscow", "MOEX"), "8": ("Africa/Johannesburg", "JSE"), "9": ("Asia/Dubai", "DFM, Tadawul"), "10": ("Asia/Kolkata", "NSE, BSE"), "11": ("Asia/Shanghai", "SSE, SZSE, HKEX, SGX"), "12": ("Asia/Tokyo", "JPX"), "13": ("Asia/Seoul", "KRX"), "14": ("Australia/Sydney", "ASX") } print("Choose the target timezone for conversion:") for key, (typ, desc) in options.items(): print(f"{key}. {typ} - {desc}") print(f"") while True: choice = input("Please enter the desired target timezone: ").strip() if choice in options: break else: print(f"Invalid choice. Please select one of: {', '.join(options.keys())}") print(f"") print(f"") return (choice, options[choice][0]) def clear_folder(folder_path): """ Delete all files inside the given folder. """ if os.path.exists(folder_path): for filename in os.listdir(folder_path): file_path = os.path.join(folder_path, filename) if os.path.isfile(file_path): os.remove(file_path) def split_to_T12(folder_path): """ Splits all CSV files in folder to seperate T1 and T2 files. Writes output to a subfolder 'T1SPLIT' and 'T2SPLIT'. Does not create empty files. Clears the 'T1SPLIT' and 'T2SPLIT' folder before conversion if it exists. """ foldername_T1 = "T1SPLIT" target_folder_T1 = os.path.join(folder_path, foldername_T1) if os.path.exists(target_folder_T1): print(f"Clearing existing folder '{target_folder_T1}'") clear_folder(target_folder_T1) else: print(f"Create folder '{target_folder_T1}'") os.makedirs(target_folder_T1, exist_ok=True) foldername_T2 = "T2SPLIT" target_folder_T2 = os.path.join(folder_path, foldername_T2) if os.path.exists(target_folder_T2): print(f"Clearing existing folder '{target_folder_T2}'") clear_folder(target_folder_T2) else: print(f"Create folder '{target_folder_T2}'") os.makedirs(target_folder_T2, exist_ok=True) csv_files = [f for f in os.listdir(folder_path) if f.lower().endswith('.csv')] for filename in csv_files: source_path = os.path.join(folder_path, filename) target_path_T1 = os.path.join(target_folder_T1, filename) target_path_T2 = os.path.join(target_folder_T2, filename) lines_to_write_T1 = [] lines_to_write_T2 = [] with open(source_path, encoding='utf-8') as source_file: for line in source_file: line = line.strip() if not line: continue columns = line.split(';') if len(columns) > 1: if columns[1] == "1": lines_to_write_T1.append(line) else: lines_to_write_T2.append(line) if lines_to_write_T1: with open(target_path_T1, 'w', encoding='utf-8') as target_file: for l in lines_to_write_T1: target_file.write(l + '\n') print(f"File '{filename}' converted and saved in '{foldername_T1}' folder.") else: print(f"File '{filename}' has no matching lines for {foldername_T1} conversion - no file created.") if lines_to_write_T2: with open(target_path_T2, 'w', encoding='utf-8') as target_file: for l in lines_to_write_T2: target_file.write(l + '\n') print(f"File '{filename}' converted and saved in '{foldername_T2}' folder.") else: print(f"File '{filename}' has no matching lines for {foldername_T2} conversion - no file created.") def convert_to_T1(folder_path, only_trades): """ Convert all CSV files in folder to T1 by filtering lines where column 2 == "1". Writes output to a subfolder 'T1'. Does not create empty files. Clears the 'T1' folder before conversion if it exists. """ if only_trades is False: foldername = "T1" else: foldername = "T1_TRADES" target_folder = os.path.join(folder_path, foldername) if os.path.exists(target_folder): print(f"Clearing existing folder '{target_folder}'") clear_folder(target_folder) else: print(f"Create folder '{target_folder}'") os.makedirs(target_folder, exist_ok=True) csv_files = [f for f in os.listdir(folder_path) if f.lower().endswith('.csv')] for filename in csv_files: source_path = os.path.join(folder_path, filename) target_path = os.path.join(target_folder, filename) lines_to_write = [] with open(source_path, encoding='utf-8') as source_file: for line in source_file: line = line.strip() if not line: continue columns = line.split(';') if len(columns) > 1 and columns[1] == "1": if only_trades is True: if columns[2] == "2": lines_to_write.append(line) else: lines_to_write.append(line) if lines_to_write: with open(target_path, 'w', encoding='utf-8') as target_file: for l in lines_to_write: target_file.write(l + '\n') print(f"File '{filename}' converted and saved in '{foldername}' folder.") else: print(f"File '{filename}' has no matching lines for {foldername} conversion - no file created.") def format_double(value): if value == int(value): return str(int(value)) else: return str(value) def convert_to_C(folder_path, interval_key, step): """ Convert all CSV files in folder to C* by resampling the data to the desired Candlestick resolution. Writes output to a subfolder 'C' follewed by the choosen timeframe (e.g. C_1m). Does not create empty files. Clears the 'C*' folder before conversion if it exists. """ target_folder = os.path.join(folder_path, f"C_{interval_key}") if os.path.exists(target_folder): print(f"Clearing existing folder '{target_folder}'") clear_folder(target_folder) else: print(f"Create folder '{target_folder}'") os.makedirs(target_folder, exist_ok=True) csv_files = [f for f in os.listdir(folder_path) if f.lower().endswith('.csv')] for filename in csv_files: src_path = os.path.join(folder_path, filename) tgt_path = os.path.join(target_folder, filename) lines_to_write = [] try: with open(src_path, encoding="utf-8") as src_file: # Candle-Variables T_Volume = 0.0 T_Open = -1.0 T_High = float("-inf") T_Low = float("inf") T_Close = -1.0 B_Open = -1.0 B_High = float("-inf") B_Low = float("inf") B_Close = -1.0 A_Open = -1.0 A_High = float("-inf") A_Low = float("inf") A_Close = -1.0 bucket_start = None bucket_end = None for line in src_file: line = line.strip() if not line: continue cols = line.split(";") if len(cols) < 5: continue if cols[1].strip() != "1": continue ts_str = cols[0].strip() year = int(ts_str[0:4]) month = int(ts_str[4:6]) day = int(ts_str[6:8]) hour = int(ts_str[8:10]) if len(ts_str) >= 10 else 0 minute = int(ts_str[10:12]) if len(ts_str) >= 12 else 0 second = int(ts_str[12:14]) if len(ts_str) >= 14 else 0 ts_sec = dt.datetime(year, month, day, hour, minute, second, tzinfo=dt.timezone.utc).timestamp() price = float(cols[3].strip()) volume = float(cols[4].strip()) typ = cols[2].strip() if bucket_start is None: bucket_end = ((ts_sec // step) + 1) * step bucket_start = bucket_end - step while ts_sec >= bucket_end: ts_out = dt.datetime.fromtimestamp(bucket_start, tz=dt.timezone.utc).strftime("%Y%m%d%H%M%S") if T_Open != -1: lines_to_write.append( f"{ts_out};2;{format_double(T_Open)};{format_double(T_High)};{format_double(T_Low)};{format_double(T_Close)};{format_double(T_Volume)}" ) if B_Open != -1: lines_to_write.append( f"{ts_out};0;{format_double(B_Open)};{format_double(B_High)};{format_double(B_Low)};{format_double(B_Close)};0" ) if A_Open != -1: lines_to_write.append( f"{ts_out};1;{format_double(A_Open)};{format_double(A_High)};{format_double(A_Low)};{format_double(A_Close)};0" ) # Reset T_Volume = 0.0 T_Open = -1.0 T_High = float("-inf") T_Low = float("inf") T_Close = -1.0 B_Open = -1.0 B_High = float("-inf") B_Low = float("inf") B_Close = -1.0 A_Open = -1.0 A_High = float("-inf") A_Low = float("inf") A_Close = -1.0 bucket_start = bucket_end bucket_end += step # Sort values if typ == "2": T_Volume += volume T_Close = price if T_Open == -1: T_Open = price if price > T_High: T_High = price if price < T_Low: T_Low = price elif typ == "0": B_Close = price if B_Open == -1: B_Open = price if price > B_High: B_High = price if price < B_Low: B_Low = price elif typ == "1": A_Close = price if A_Open == -1: A_Open = price if price > A_High: A_High = price if price < A_Low: A_Low = price # write last Candle if bucket_start is not None: ts_out = dt.datetime.fromtimestamp(bucket_start, tz=dt.timezone.utc).strftime("%Y%m%d%H%M%S") if T_Open != -1: lines_to_write.append( f"{ts_out};2;{format_double(T_Open)};{format_double(T_High)};{format_double(T_Low)};{format_double(T_Close)};{format_double(T_Volume)}" ) if B_Open != -1: lines_to_write.append( f"{ts_out};0;{format_double(B_Open)};{format_double(B_High)};{format_double(B_Low)};{format_double(B_Close)};0" ) if A_Open != -1: lines_to_write.append( f"{ts_out};1;{format_double(A_Open)};{format_double(A_High)};{format_double(A_Low)};{format_double(A_Close)};0" ) if lines_to_write: with open(tgt_path, "w", encoding="utf-8") as tgt_file: tgt_file.write("\n".join(lines_to_write) + "\n") print(f"File '{filename}' converted -> interval {interval_key}") else: print(f"No candles for {filename}") except Exception as e: print(f"Error processing file '{filename}': {e}") def convert_TZ(folder_path, target_tz): """ Convert all CSV files in folder to a new timezone by resampling the data from UTC to the desired timezone. Writes output to a subfolder which is called like the target timezone. Does not create empty files. Clears the timezone folder before conversion if it exists. """ tz = ZoneInfo(target_tz) target_folder = os.path.join(folder_path, target_tz.replace("/", "_")) if os.path.exists(target_folder): print(f"Clearing existing folder '{target_folder}'") clear_folder(target_folder) else: print(f"Create folder '{target_folder}'") os.makedirs(target_folder, exist_ok=True) csv_files = [f for f in os.listdir(folder_path) if f.lower().endswith('.csv')] for filename in csv_files: src_path = os.path.join(folder_path, filename) tgt_path = os.path.join(target_folder, filename) lines_to_write = [] try: with open(src_path, encoding="utf-8") as src_file: for line in src_file: line = line.strip() if not line: continue parts = line.split(";", 1) timestamp = parts[0] if len(timestamp) == 12: # YYYYMMDDhhmm → + "00" seconds timestamp = timestamp + "00" if len(timestamp) == 14: # YYYYMMDDhhmmss dt_obj = dt.datetime.strptime(timestamp, "%Y%m%d%H%M%S") dt_obj = dt_obj.replace(tzinfo=ZoneInfo("UTC")) dt_local = dt_obj.astimezone(tz) new_timestamp = dt_local.strftime("%Y%m%d%H%M%S") elif len(timestamp) == 20: # YYYYMMDDhhmmssffffff (14 + 6 microseconds) dt_obj = dt.datetime.strptime(timestamp, "%Y%m%d%H%M%S%f") dt_obj = dt_obj.replace(tzinfo=ZoneInfo("UTC")) dt_local = dt_obj.astimezone(tz) new_timestamp = dt_local.strftime("%Y%m%d%H%M%S%f") else: # Unknown format → leave as is new_timestamp = timestamp lines_to_write.append(new_timestamp + f";" + parts[1]) if lines_to_write: with open(tgt_path, "w", encoding="utf-8") as tgt_file: tgt_file.write("\n".join(lines_to_write) + "\n") print(f"File '{filename}' converted to {target_tz}") else: print(f"No lines to write to {filename}") except Exception as e: print(f"Error processing file '{filename}': {e}") def main(): print_header() folder_path = input("Please enter the source folder path with extracted data from MarketTick: ").strip() if folder_path.lower().endswith(".zip") or folder_path.lower().endswith(".7z"): print(f"Error: Please unpack the archive first and then specify the folder in which the files were unpacked when you run this script again.") return if not os.path.isdir(folder_path): # check if folder exists print(f"Error: Path '{folder_path}' does not exist or is not a directory.") return csv_files = [f for f in os.listdir(folder_path) if f.lower().endswith('.csv')] if not csv_files: print("No CSV files found in the folder.") return first_file = csv_files[0] first_file_path = os.path.join(folder_path, first_file) print(f"Analyzing...") types = { "T1": ("Level1 Tick Data"), "T2": ("Level2 Tick Data"), "C1": ("1minute OHLCV Candlesticks"), } detected_type = determine_type(first_file_path) print(f"Detected type of the files is: {detected_type} ({types[detected_type]})") print(f"") print(f"") target_type = get_conversion_options(detected_type) print(f"") if target_type == "T1": convert_to_T1(folder_path, False) elif target_type == "T1TRADE": convert_to_T1(folder_path, True) elif target_type == "C": step = get_conversion_steps_C() convert_to_C(folder_path, step[0], step[1]) elif target_type == "TZ": try: test = ZoneInfo("America/New_York") except ZoneInfoNotFoundError: print("Error: 'tzdata' is not installed. Please install it with 'pip install tzdata' to use this function.") exit(1) tzone = get_conversion_timezone() convert_TZ(folder_path, tzone[1]) elif target_type == "T2SPLIT": split_to_T12(folder_path) elif target_type == "AddOn_NT": MarketTick_Resample_NT.convert_files(folder_path) elif target_type == "AddOn_MT5": MarketTick_Resample_MT5.convert_files(folder_path) elif target_type == "AddOn_SC": MarketTick_Resample_SC.convert_files(folder_path) elif target_type == "AddOn_MC": MarketTick_Resample_MC.convert_files(folder_path) elif target_type == "AddOn_BT": MarketTick_Resample_BT.convert_files(folder_path) if __name__ == "__main__": try: main() except KeyboardInterrupt: print(f"") print(f"") print(f"👋 Goodbye!")