├── .DS_Store ├── .gitignore ├── 2factor_momentum.py ├── Data ├── data.obj ├── hist.xlsx └── sp500_data.xlsx ├── README.md ├── backtests ├── binance_LBMOM.png ├── dwx_LBMOM.png ├── dwx_LSMOM.png ├── oan_LBMOM.png ├── oan_LSMOM.png └── oan_SKPRM.png ├── brokerage ├── .DS_Store ├── binance │ ├── DataClient.py │ ├── ServiceClient.py │ ├── TradeClient.py │ └── binanceUM.py ├── darwinex │ ├── .DS_Store │ ├── DWX_ZeroMQ_Connector_v2_0_1_RC8.py │ ├── ServiceClient.py │ ├── TradeClient.py │ ├── assets.json │ ├── darwinex.py │ ├── htmls │ │ ├── commodities.txt │ │ ├── fx.txt │ │ ├── indices.txt │ │ ├── nasdaq.txt │ │ └── nyse.txt │ └── scraper.py └── oanda │ ├── .DS_Store │ ├── ServiceClient.py │ ├── TradeClient.py │ └── oanda.py ├── config ├── auth_config.json ├── crypto_config.py ├── dwx_config.json ├── oan_config.json └── portfolio_config.json ├── crypto_momentum.py ├── diagnostics ├── HANGUKQUANT │ ├── dwx_leverage.png │ ├── dwx_scatter.png │ ├── dwx_weights.png │ ├── oan_leverage.png │ ├── oan_scatter.png │ └── oan_weights.png ├── LBMOM │ ├── binance_leverage.png │ ├── binance_scatter.png │ ├── binance_weights.png │ ├── dwx_leverage.png │ ├── dwx_scatter.png │ ├── dwx_weights.png │ ├── oan_leverage.png │ ├── oan_scatter.png │ └── oan_weights.png ├── LSMOM │ ├── dwx_leverage.png │ ├── dwx_scatter.png │ ├── dwx_weights.png │ ├── oan_leverage.png │ ├── oan_scatter.png │ └── oan_weights.png └── SKPRM │ ├── oan_leverage.png │ ├── oan_scatter.png │ └── oan_weights.png ├── dwx-zeromq-connector-master ├── .gitattributes ├── CHANGELOG.md ├── DWX_ZeroMQ_Server_v2.0.1_RC8.mq4 ├── LICENSE ├── README.md ├── dependencies │ ├── README.md │ ├── mql-zmq-master.zip │ └── mql-zmq-master │ │ └── mql-zmq-master │ │ ├── ALIPAY.JPG │ │ ├── Include │ │ ├── Mql │ │ │ └── Lang │ │ │ │ ├── Error.mqh │ │ │ │ ├── GlobalVariable.mqh │ │ │ │ ├── Mql.mqh │ │ │ │ └── Native.mqh │ │ └── Zmq │ │ │ ├── AtomicCounter.mqh │ │ │ ├── Context.mqh │ │ │ ├── Errno.mqh │ │ │ ├── Socket.mqh │ │ │ ├── SocketOptions.mqh │ │ │ ├── Z85.mqh │ │ │ ├── Zmq.mqh │ │ │ └── ZmqMsg.mqh │ │ ├── LICENSE │ │ ├── Library │ │ ├── MT4 │ │ │ ├── libsodium.dll │ │ │ └── libzmq.dll │ │ ├── MT5 │ │ │ ├── libsodium.dll │ │ │ └── libzmq.dll │ │ └── VC2010 │ │ │ ├── x64 │ │ │ ├── libsodium.dll │ │ │ └── libzmq.dll │ │ │ └── x86 │ │ │ ├── libsodium.dll │ │ │ └── libzmq.dll │ │ ├── README.md │ │ └── Scripts │ │ ├── Test │ │ └── TestZmq.mq4 │ │ └── ZeroMQGuideExamples │ │ ├── Chapter1 │ │ ├── HelloWorldClient.mq4 │ │ ├── HelloWorldServer.mq4 │ │ ├── TaskEvent.mq4 │ │ ├── TaskSink.mq4 │ │ ├── TaskWorker.mq4 │ │ ├── VersionReporting.mq4 │ │ ├── WeatherUpdateClient.mq4 │ │ └── WeatherUpdateServer.mq4 │ │ ├── Chapter2 │ │ ├── MSPoller.mq4 │ │ ├── RRBroker.mq4 │ │ ├── RRClient.mq4 │ │ ├── RRWorker.mq4 │ │ └── WUProxy.mq4 │ │ └── Chapter3 │ │ ├── RTReqBroker.mq4 │ │ └── RTReqWorker.mq4 ├── resources │ ├── README.md │ └── images │ │ ├── 1200x628-twitter-4.jpg │ │ ├── InAction_ZeroMQ_Server_Publishing_Symbol_Data.gif │ │ ├── README.md │ │ ├── ZeroMQ_Server_Publishing_Symbol_Data.gif │ │ ├── dwx-zeromq-infographic-1.png │ │ ├── expert-inputs.png │ │ └── expert-inputs_old.png └── v2.0.1 │ ├── README.md │ ├── mql4 │ └── README.md │ └── python │ ├── README.md │ ├── api │ ├── DWX_ZeroMQ_Connector_v2_0_1_RC8.py │ ├── README.md │ └── requirements.txt │ └── examples │ ├── README.md │ └── template │ ├── README.md │ ├── modules │ ├── DWX_ZMQ_Execution.py │ ├── DWX_ZMQ_Reporting.py │ └── README.md │ └── strategies │ ├── README.md │ ├── base │ ├── DWX_ZMQ_Strategy.py │ └── README.md │ ├── coin_flip_traders_v1.0.py │ ├── prices_subscriptions.py │ ├── rates_historic.py │ └── rates_subscriptions.py ├── factor_framework ├── pipeline.py └── run.py ├── main.py ├── playground ├── b_bands.ipynb ├── general_factor.ipynb ├── long_symbols.csv ├── momentum_2factor.ipynb ├── momentum_2factor_avg_trade.ipynb ├── momentum_explore.ipynb ├── rank.csv ├── short_symbols.csv └── trend.ipynb ├── quantlib.egg-info ├── PKG-INFO ├── SOURCES.txt ├── dependency_links.txt ├── not-zip-safe ├── requires.txt └── top_level.txt ├── quantlib ├── .DS_Store ├── __init__.py ├── backtest_utils.py ├── crypto_data_utils.py ├── crypto_format_utils.py ├── data_utils.py ├── diagnostics_utils.py ├── general_utils.py ├── indicators_cal.py └── printer_utils.py ├── requirements.txt ├── script.py ├── setup.py ├── subsystems ├── .DS_Store ├── LBMOM │ ├── .DS_Store │ ├── config.json │ ├── crypto.py │ ├── dwx_config.json │ ├── oan_config.json │ ├── oan_config_backup.json │ └── subsys.py ├── LSMOM │ ├── .DS_Store │ ├── dwx_config.json │ ├── oan_config.json │ ├── oan_config_backup.json │ └── subsys.py └── SKPRM │ ├── .DS_Store │ ├── oan_config.json │ └── subsys.py └── test.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.xlsx 3 | *.obj 4 | *.png 5 | *.DS_Store 6 | .env 7 | *.csv -------------------------------------------------------------------------------- /2factor_momentum.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pandas as pd 3 | from collections import defaultdict 4 | 5 | from dateutil.relativedelta import relativedelta 6 | import quantlib.crypto_data_utils as crypto_du 7 | from brokerage.binance.TradeClient import TradeClient 8 | 9 | import config.crypto_config as conf 10 | 11 | import warnings 12 | warnings.filterwarnings("ignore") 13 | 14 | LONG_RANK = [(0, 3), (1, 3), (4, 0)] 15 | lw = [0.25, 0.25, 0.5] 16 | SHORT_RANK = [(0, 0), (0, 2), (1, 0)] 17 | sw = [0.4, 0.2, 0.4] 18 | rank_weight_dict = {} 19 | for i, rank in enumerate(LONG_RANK): 20 | rank_weight_dict[rank] = lw[i] 21 | for i, rank in enumerate(SHORT_RANK): 22 | rank_weight_dict[rank] = sw[i] 23 | print (rank_weight_dict) 24 | 25 | def prepare_data(limit=100): 26 | """ 27 | Get Data, update database 28 | 29 | Return: the extended historical data, all instruments 30 | """ 31 | 32 | db_file = "crypto_ohlv_4h.xlsx" 33 | db_file_path = f"./Data/{db_file}" 34 | database_df = pd.read_excel(db_file_path).set_index("open_time") 35 | 36 | new_df, instruments = crypto_du.get_crypto_futures_df(interval="4h", limit=limit) 37 | merge_df = pd.concat([database_df, new_df]) 38 | merge_df = merge_df[~merge_df.index.duplicated(keep='last')].sort_index() 39 | merge_df.to_excel(db_file_path) 40 | # Historical_data would include everything till now, also the current not finished kline 41 | historical_data = crypto_du.extend_dataframe(traded=instruments, df=merge_df, interval="4h") 42 | historical_data.to_excel("crypto_historical_4h.xlsx") 43 | 44 | return historical_data, instruments 45 | 46 | def get_symbol_rank(rank_df, symbol): 47 | rank_df = rank_df.to_frame().transpose() 48 | for col in rank_df.columns: 49 | if col[:6] == symbol[:6]: 50 | return int(rank_df[col]) 51 | 52 | def get_volitility(inst): 53 | return float(df.iloc[-1][f"{inst} % ret vol"]) 54 | 55 | def generate_rank_dict(rank1, rank2, instruments): 56 | rank_dict = defaultdict(list) 57 | for inst in instruments: 58 | inst_details = { 59 | "symbol": inst, 60 | "vol_weight": 1 / (get_volitility(inst) + 0.001) 61 | } 62 | r1, r2 = get_symbol_rank(rank1, inst), get_symbol_rank(rank2, inst) 63 | rank_dict[(r1, r2)].append(inst_details) 64 | 65 | # Set weights 66 | rank_dict_with_weights = defaultdict(list) 67 | for k, v in rank_dict.items(): 68 | if k not in rank_weight_dict: continue 69 | if not v: continue 70 | try: 71 | total_vol_weight = sum([x["vol_weight"] for x in v]) 72 | for details in v: 73 | details["weight"] = rank_weight_dict[k] * details["vol_weight"] / total_vol_weight 74 | rank_dict_with_weights[k].append(details) 75 | except Exception as e: 76 | print (e) 77 | for details in v: 78 | details["weight"] = rank_weight_dict[k] / len(v) 79 | rank_dict_with_weights[k].append(details) 80 | 81 | return rank_dict_with_weights 82 | 83 | 84 | def generate_signal(historical_data, instruments): 85 | """ 86 | Generate signals 87 | """ 88 | global df 89 | df = historical_data.copy() 90 | LOOK_BACK = 62 91 | LOOK_AHEAD = 15 92 | K1, K2 = 5, 4 93 | IGNORES = 5 # We do not want to count the closest momentum for possible reversion 94 | 95 | active_insts = [] 96 | ret_cols = [] 97 | SHIFT_UNITS = LOOK_BACK + IGNORES 98 | for inst in instruments: 99 | if df.iloc[-SHIFT_UNITS][f"{inst} active"] == False: 100 | print ("Not active symbols: ", inst) 101 | continue 102 | active_insts.append(inst) 103 | ret_col_name = "{} {} ret".format(inst, LOOK_BACK) 104 | ret_cols.append(ret_col_name) 105 | df[ret_col_name] = df["{} close".format(inst)].shift(IGNORES) / df["{} close".format(inst)].shift(SHIFT_UNITS) - 1 106 | 107 | # Modify last row to get the second feature 108 | second_feature_cols = [] 109 | last = df[ret_cols].tail(1).reset_index(drop=True) 110 | for inst in active_insts: 111 | col_name = f"{inst} {LOOK_BACK} max bar ret" 112 | second_feature_cols.append(col_name) 113 | last.loc[0, col_name] = max(df.iloc[-SHIFT_UNITS:-IGNORES][f"{inst} % ret"]) 114 | 115 | rank1 = pd.qcut(last.loc[0, ret_cols], K1, labels=False) 116 | rank2 = pd.qcut(last.loc[0, second_feature_cols], K2, labels=False) 117 | 118 | # Based on rank generate symbols to be longed and symbols to be shorted 119 | rank_dict = generate_rank_dict(rank1, rank2, active_insts) 120 | 121 | long_list, short_list = [], [] 122 | for long_rank in LONG_RANK: 123 | long_list += rank_dict[long_rank] 124 | for short_rank in SHORT_RANK: 125 | short_list += rank_dict[short_rank] 126 | 127 | #print ("Long list: ", long_list) 128 | #print ("Short list: ", short_list) 129 | return long_list, short_list 130 | 131 | def execute_orders(long_list, short_list, test=True): 132 | """ 133 | Execute orders, if test, no orders will be made 134 | """ 135 | client = TradeClient() 136 | curr_positions = client.get_account_positions() 137 | if test: 138 | print (curr_positions) 139 | return 140 | 141 | long_symbols = [x["symbol"] for x in long_list] 142 | short_symbols = [x["symbol"] for x in short_list] 143 | 144 | # Close positions 145 | for symbol, details in curr_positions.items(): 146 | position_amount = details['positionAmt'] 147 | if symbol in long_symbols and position_amount > 0: 148 | continue 149 | if symbol in short_symbols and position_amount < 0: 150 | continue 151 | client.close_positon(symbol, details) 152 | 153 | # Open positons 154 | curr_positions = client.get_account_positions() 155 | 156 | for i, symbol in enumerate(long_symbols): 157 | if symbol not in curr_positions: 158 | params = conf.BUY_PARAMS.copy() 159 | params["collateral"] = params["collateral"] * long_list[i]["weight"] 160 | print (symbol, params) 161 | client.open_position(symbol, params) 162 | time.sleep(0.3) 163 | 164 | for i, symbol in enumerate(short_symbols): 165 | if symbol not in curr_positions: 166 | params = conf.SELL_PARAMS.copy() 167 | params["collateral"] = params["collateral"] * short_list[i]["weight"] 168 | print (symbol, params) 169 | client.open_position(symbol, params) 170 | time.sleep(0.3) 171 | 172 | print ("Orders have been placed!") 173 | 174 | 175 | def main(use_disk=False, test=True): 176 | if not use_disk: 177 | historical_data, instruments = prepare_data(limit=100) 178 | else: 179 | historical_data = pd.read_excel("./crypto_historical_4h.xlsx", engine="openpyxl", index_col='open_time') 180 | instruments = crypto_du.get_symbols_from_df(historical_data) 181 | 182 | long_list, short_list = generate_signal(historical_data, instruments) 183 | print (long_list) 184 | execute_orders(long_list, short_list, test) 185 | 186 | if __name__ == "__main__": 187 | print ("Working!") 188 | main(use_disk=False, test=True) 189 | #main(use_disk=False, test=False) 190 | -------------------------------------------------------------------------------- /Data/data.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/Data/data.obj -------------------------------------------------------------------------------- /Data/hist.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/Data/hist.xlsx -------------------------------------------------------------------------------- /Data/sp500_data.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/Data/sp500_data.xlsx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multi-Strategy Quant System 2 | This is a Python-based repository for a multi-strategy quant system. It provides a framework for implementing and testing various quantitative trading strategies on financial time series data, and can be used to generate buy/sell signals based on the outputs of those strategies. 3 | 4 | Original work was from the course of @hangukQuant [https://github.com/hangukquant] and this repo made some changes to research on the momentum factor. 5 | 6 | ## Features 7 | - Modular and extensible framework for implementing and testing quantitative trading strategies 8 | - Multiple pre-built strategies for backtesting and live trading 9 | - Supports data from multiple sources, including CSV files and live market data feeds 10 | - Fully customizable and configurable via configuration files 11 | - Real-time monitoring of portfolio performance and positions 12 | - Comprehensive documentation and examples to get you started 13 | ## Installation 14 | To install the multi-strategy quant system, follow these steps: 15 | 16 | 1. Clone the repository to your local machine: git clone https://github.com/yourusername/multi-strategy-quant-system.git 17 | 2. Install the required packages by running pip install -r requirements.txt 18 | ## Getting Started 19 | To get started with the multi-strategy quant system, follow these steps: 20 | 21 | 1. Review the documentation in the docs directory to gain an understanding of the system's architecture and how to use it. 22 | 2. Modify the configuration file in config/config.yml to specify your preferred strategies, data sources, and other system settings. 23 | 3. Run the system by executing python main.py in your terminal. The system will begin to process your data and generate buy/sell signals based on your chosen strategies. 24 | -------------------------------------------------------------------------------- /backtests/binance_LBMOM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/backtests/binance_LBMOM.png -------------------------------------------------------------------------------- /backtests/dwx_LBMOM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/backtests/dwx_LBMOM.png -------------------------------------------------------------------------------- /backtests/dwx_LSMOM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/backtests/dwx_LSMOM.png -------------------------------------------------------------------------------- /backtests/oan_LBMOM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/backtests/oan_LBMOM.png -------------------------------------------------------------------------------- /backtests/oan_LSMOM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/backtests/oan_LSMOM.png -------------------------------------------------------------------------------- /backtests/oan_SKPRM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/backtests/oan_SKPRM.png -------------------------------------------------------------------------------- /brokerage/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/brokerage/.DS_Store -------------------------------------------------------------------------------- /brokerage/binance/DataClient.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class DataClient(): 4 | 5 | def __init__(self): 6 | self.interval = None 7 | self.symbols = None 8 | 9 | -------------------------------------------------------------------------------- /brokerage/binance/ServiceClient.py: -------------------------------------------------------------------------------- 1 | #aids in the order logic and helps integrate the brokerage into the system, no external dependency 2 | 3 | 4 | class ServiceClient(): 5 | 6 | def __init__(self, brokerage_config=None): 7 | self.brokerage_config = brokerage_config 8 | 9 | #lets implement some API interface that our TradeClient would use, and later we will see how they become useful 10 | 11 | def get_size_config(self, inst): 12 | order_min_contracts = 1 #minimum size of order 13 | contract_size = 1 #size in units of a contract 14 | return order_min_contracts, contract_size 15 | 16 | def get_order_specs(self, inst, units, current_contracts): 17 | #this is an internal `order` object that is passed around different components of the trading system 18 | #it is the `settings` of an order item, that all brokerages should implement to meet internal needs 19 | order_min_contracts, contract_size = self.get_size_config(inst) 20 | order_min_units = self.contracts_to_units(label=inst, contracts=order_min_contracts) 21 | optimal_min_order = units / order_min_units 22 | rounded_min_order = round(optimal_min_order) 23 | specs = { 24 | "instrument": inst, 25 | "scaled_units": units, 26 | "contract_size": contract_size, 27 | "order_min_contracts": order_min_contracts, 28 | "order_min_units": order_min_units, 29 | "optimal_contracts": optimal_min_order * order_min_contracts, 30 | "rounded_contracts": rounded_min_order * order_min_contracts, 31 | "current_contracts": current_contracts, 32 | "current_units": self.contracts_to_units(inst, current_contracts) 33 | } 34 | return specs 35 | 36 | def contracts_to_units(self, label, contracts): 37 | order_min_contracts, contract_size = self.get_size_config(label) 38 | return contracts * contract_size 39 | 40 | def units_to_contracts(self, label, units): 41 | #these are conversions between contract and unit sizing, for instance how many units are there in a micro contract, a mini contract etc? 42 | #these depend on the brokerage specifications! 43 | order_min_contracts, contract_size = self.get_size_config(label) 44 | return units / contract_size 45 | 46 | 47 | def is_inertia_override(self, percent_change): 48 | return percent_change > 0.05 #positional inertia to prevent too frequent trading 49 | 50 | def code_to_label_nomenclature(self, code): 51 | #these are external to internal conversions between instrument naming 52 | #for instance a EUR/USD contract can be: EUR_USD, EUR/USD, EUR;USD etc etc. let code be the brokerage code, and the label be the internal name 53 | return code 54 | 55 | def label_to_code_nomenclature(self, label): 56 | return label 57 | -------------------------------------------------------------------------------- /brokerage/binance/TradeClient.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import pandas as pd 4 | import datetime 5 | from dotenv import load_dotenv 6 | 7 | from binance.um_futures import UMFutures 8 | from quantlib.crypto_format_utils import format_price, format_quantity 9 | 10 | from collections import defaultdict 11 | 12 | class TradeClient(): 13 | 14 | def __init__(self, brokerage_config=None, auth_config=None, service_client=None): 15 | load_dotenv() 16 | self.key=os.getenv("KEY") 17 | self.secret =os.getenv("SECRET") 18 | self.client = UMFutures(key=self.key, secret=self.secret) 19 | self.mark_price = None 20 | 21 | """ 22 | We are interested in getting 23 | 1. Capital 24 | 2. Positions 25 | 3. Submit Orders 26 | 4. Get OHLCV data etc 27 | """ 28 | def get_mark_price(self): 29 | """Get the current market mark price when needed""" 30 | self.mark_price = self.client.mark_price() 31 | 32 | def get_account_details(self): 33 | try: 34 | return self.client.account() 35 | except Exception as err: 36 | print(err) 37 | 38 | def get_account_summary(self): 39 | pass 40 | 41 | def get_account_instruments(self): 42 | #Get the list of tradable instruments for the given Account. The list of tradeable instruments is dependent on the regulatory division that the Account is located in 43 | #we can get financing rates for instruments here , etc 44 | try: 45 | positions = self.get_account_details()['positions'] 46 | instruments = [x['symbol'] for x in positions] 47 | return instruments 48 | except Exception as e: 49 | print (e) 50 | 51 | def get_account_capital(self): 52 | try: 53 | return float(self.get_account_summary()["totalWalletBalance"]) 54 | except Exception as err: 55 | pass 56 | 57 | def get_account_available_balance(self): 58 | try: 59 | return float(self.get_account_summary()["availableBalance"]) 60 | except Exception as e: 61 | print (e) 62 | 63 | #we can try to enter some positions or trades to see what the return result looks like 64 | #we see that the Oanda brokerage automatically performs netting of positions 65 | #we bought 30 EUR_USD units, sold 6, and we have 24 units of open positions 66 | #do note that this is not the same for every brokerage. In some cases, brokerages allow two open trades of opposing direction without netting 67 | #this would cause the txn fees to increase! 68 | def get_account_positions(self): 69 | positions_data = self.get_account_details()["positions"] 70 | positions = {} 71 | for entry in positions_data: 72 | instrument = entry["symbol"] 73 | positionAmt = float(entry["positionAmt"]) 74 | entryPrice = float(entry["entryPrice"]) 75 | unrealizedProfit = float(entry["unrealizedProfit"]) 76 | if positionAmt != 0: 77 | positions[instrument] = { 78 | "positionAmt": positionAmt, 79 | "entryPrice": entryPrice, 80 | "unrealizedProfit": unrealizedProfit, 81 | } 82 | return positions 83 | 84 | def get_account_trades(self): 85 | pass 86 | 87 | def format_date(self, series): 88 | #series in the form :: 2021-09-21T21:00:00.000000000Z 89 | ddmmyy = series.split("T")[0].split("-") 90 | return datetime.date(int(ddmmyy[0]), int(ddmmyy[1]), int(ddmmyy[2])) 91 | 92 | def get_ohlcv(self, instrument, count, granularity): 93 | pass 94 | 95 | def set_isolated_leverage(self, symbol, leverage): 96 | try: 97 | res = self.client.change_leverage(symbol=symbol, leverage=leverage) 98 | res = self.client.change_margin_type( 99 | symbol=symbol, marginType="ISOLATED") 100 | except Exception as e: 101 | print (e) 102 | print ("Seems already isolated!") 103 | 104 | def repeat_orders(self, kwargs, times=5): 105 | response = None 106 | for i in range(times): 107 | try: 108 | response = self.client.new_order(**kwargs) 109 | except Exception as e: 110 | continue 111 | break 112 | return response 113 | 114 | def make_market_order(self, symbol, order_config={}, open=False): 115 | # quantity should indicate the side 116 | if open: 117 | self.set_isolated_leverage(symbol=symbol, leverage=order_config["leverage"]) 118 | MARKET_SLIPPERAGE = 0.03 119 | quantity = float(order_config["quantity"]) 120 | reduce_only = order_config.get("reduceOnly", False) 121 | if quantity < 0: 122 | position_side = "SELL" 123 | price = float(order_config["price"]) * (1-MARKET_SLIPPERAGE) 124 | else: 125 | position_side = "BUY" 126 | price = float(order_config["price"]) * (1+MARKET_SLIPPERAGE) 127 | 128 | params = { 129 | 'symbol': symbol, 130 | 'side': position_side, 131 | 'type': 'LIMIT', 132 | 'quantity': format_quantity(abs(quantity), price), 133 | 'price': format_price(price), 134 | 'timeInForce': 'GTC', 135 | 'reduceOnly': reduce_only 136 | } 137 | print (params) 138 | res = self.repeat_orders(params) 139 | return res 140 | 141 | def close(self, symbol): 142 | positions = self.get_account_positions() 143 | try: 144 | details = positions[symbol] 145 | self.close_positon(symbol, details) 146 | except: 147 | print (f"There is no such position for {symbol}!") 148 | return 149 | 150 | def close_positon(self, symbol, details): 151 | try: 152 | quantity = 0-details['positionAmt'] # Take the opposite to close a position 153 | price = self.get_current_price(symbol) 154 | price = format_price(price) 155 | 156 | order_config = { 157 | "reduceOnly": True, 158 | "quantity": format_quantity(quantity, price), 159 | "price": price 160 | } 161 | response = self.make_market_order(symbol, order_config=order_config) 162 | return response 163 | except Exception as e: 164 | print (f"Error when closing position for {symbol}!") 165 | print (e) 166 | 167 | def open_position(self, symbol, param): 168 | try: 169 | price = self.get_current_price(symbol) 170 | price = format_price(price) 171 | nominal_usd = param['leverage'] * param['collateral'] 172 | 173 | quantity = nominal_usd / price 174 | quantity = format_quantity(quantity, price) 175 | if param['side'] == "SELL": 176 | quantity = -quantity 177 | order_config = { 178 | "quantity": quantity, 179 | "price": price, 180 | "leverage": param['leverage'] 181 | } 182 | response = self.make_market_order(symbol, order_config=order_config, open=True) 183 | return response 184 | except Exception as e: 185 | print (f"Error when opening position for {symbol}!") 186 | print (e) 187 | 188 | def get_current_price(self, symbol): 189 | if not self.mark_price: 190 | self.get_mark_price() 191 | for element in self.mark_price: 192 | if element['symbol'] == symbol: 193 | return float(element['markPrice']) 194 | return 195 | 196 | 197 | if __name__ == "__main__": 198 | trade_client = TradeClient() 199 | symbol = "WAVESUSDT" 200 | order_config = { 201 | "quantity": 20, 202 | "price": 3.05, 203 | "leverage": 3 204 | } 205 | #trade_client.market_order(symbol, order_config) 206 | #print (trade_client.get_account_details()['positions']) 207 | #print (trade_client.client.mark_price()) 208 | 209 | BUY_PARAMS = { 210 | "side": "BUY", 211 | "leverage": 3, 212 | "collateral": 10, 213 | } 214 | trade_client.close(symbol) -------------------------------------------------------------------------------- /brokerage/binance/binanceUM.py: -------------------------------------------------------------------------------- 1 | from brokerage.binance.TradeClient import TradeClient 2 | from brokerage.binance.ServiceClient import ServiceClient 3 | from brokerage.binance.DataClient import DataClient 4 | 5 | class Binance(): 6 | 7 | def __init__(self, brokerage_config=None, auth_config=None): 8 | self.service_client = ServiceClient(brokerage_config=brokerage_config) 9 | self.trade_client = TradeClient(auth_config=auth_config) 10 | self.data_client = DataClient() 11 | #lets create a service class and trade class for Oanda 12 | 13 | def get_service_client(self): 14 | return self.service_client 15 | 16 | def get_trade_client(self): 17 | return self.trade_client 18 | 19 | def get_data_client(self): 20 | return self.data_client -------------------------------------------------------------------------------- /brokerage/darwinex/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/brokerage/darwinex/.DS_Store -------------------------------------------------------------------------------- /brokerage/darwinex/ServiceClient.py: -------------------------------------------------------------------------------- 1 | #aids in the order logic and helps integrate the brokerage into the system, no external dependency 2 | 3 | class ServiceClient(): 4 | 5 | def __init__(self, brokerage_config=None): 6 | self.brokerage_config = brokerage_config 7 | #we need to retrieve the configurations about the contract sizing et cetera 8 | 9 | #lets implement some API interface that our TradeClient would use, and later we will see how they become useful 10 | 11 | def get_size_config(self, inst): 12 | if inst in self.brokerage_config["fx"]: 13 | return self.brokerage_config["order_min_contracts"]["fx"], self.brokerage_config["contract_size"]["fx"] 14 | elif inst in self.brokerage_config["equities"]: 15 | return self.brokerage_config["order_min_contracts"]["equities"], self.brokerage_config["contract_size"]["equities"] 16 | elif inst in self.brokerage_config["commodities"]: 17 | return self.brokerage_config["order_min_contracts"][inst], self.brokerage_config["contract_size"][inst] 18 | else: 19 | print("unknown asset") 20 | exit() #lets assume our asset universe is fx, equities and commodities, lets also assume we only trade USD pairs in FX 21 | 22 | def get_order_specs(self, inst, units, current_contracts): 23 | #this is an internal `order` object that is passed around different components of the trading system 24 | #it is the `settings` of an order item, that all brokerages should implement to meet internal needs 25 | order_min_contracts, contract_size = self.get_size_config(inst) 26 | order_min_units = self.contracts_to_units(label=inst, contracts=order_min_contracts) 27 | optimal_min_order = units / order_min_units 28 | rounded_min_order = round(optimal_min_order) 29 | specs = { 30 | "instrument": inst, 31 | "scaled_units": round(units, 5), 32 | "contract_size": contract_size, 33 | "order_min_contracts": order_min_contracts, 34 | "order_min_units": order_min_units, 35 | "optimal_contracts": round(optimal_min_order * order_min_contracts, 5), 36 | "rounded_contracts": round(rounded_min_order * order_min_contracts, 5), 37 | "current_contracts": current_contracts, 38 | "current_units": self.contracts_to_units(inst, current_contracts) 39 | } 40 | return specs 41 | 42 | def contracts_to_units(self, label, contracts): 43 | order_min_contracts, contract_size = self.get_size_config(label) 44 | return contracts * contract_size 45 | 46 | def units_to_contracts(self, label, units): 47 | #these are conversions between contract and unit sizing, for instance how many units are there in a micro contract, a mini contract etc? 48 | #these depend on the brokerage specifications! 49 | order_min_contracts, contract_size = self.get_size_config(label) 50 | return units / contract_size 51 | 52 | 53 | def is_inertia_override(self, percent_change): 54 | return percent_change > 0.05 #positional inertia to prevent too frequent trading 55 | 56 | def code_to_label_nomenclature(self, code): 57 | #these are external to internal conversions between instrument naming 58 | #for instance a EUR/USD contract can be: EUR_USD, EUR/USD, EUR;USD etc etc. let code be the brokerage code, and the label be the internal name 59 | if code in self.brokerage_config["equities"]: 60 | return code 61 | else: 62 | if len(code) == 6: 63 | label = code[0:3] + "_" + code[3:] 64 | if label in self.brokerage_config["fx"] or label in self.brokerage_config["commodities"]: 65 | return label 66 | return code 67 | 68 | def label_to_code_nomenclature(self, label): 69 | return label.replace("_", "") 70 | -------------------------------------------------------------------------------- /brokerage/darwinex/assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "nasdaq": [ 3 | "AAL", 4 | "AAPL", 5 | "ADBE", 6 | "ADI", 7 | "ADP", 8 | "ADSK", 9 | "AMAT", 10 | "AMD", 11 | "AMGN", 12 | "AMZN", 13 | "ATVI", 14 | "AVGO", 15 | "BIIB", 16 | "BKNG", 17 | "CHTR", 18 | "CMCSA", 19 | "CME", 20 | "COST", 21 | "CSCO", 22 | "CSX", 23 | "CTSH", 24 | "DLTR", 25 | "EA", 26 | "EBAY", 27 | "EXPE", 28 | "FAST", 29 | "FB", 30 | "FISV", 31 | "FITB", 32 | "FOX", 33 | "FOXA", 34 | "GILD", 35 | "GOOG", 36 | "GOOGL", 37 | "ILMN", 38 | "INTC", 39 | "INTU", 40 | "ISRG", 41 | "KHC", 42 | "KLAC", 43 | "LRCX", 44 | "MAR", 45 | "MCHP", 46 | "MDLZ", 47 | "MSFT", 48 | "MU", 49 | "NFLX", 50 | "NTAP", 51 | "NVDA", 52 | "ORLY", 53 | "PEP", 54 | "PYPL", 55 | "QCOM", 56 | "REGN", 57 | "ROST", 58 | "SBUX", 59 | "SPLK", 60 | "SWKS", 61 | "TMUS", 62 | "TSLA", 63 | "TTWO", 64 | "TXN", 65 | "ULTA", 66 | "VRTX", 67 | "WBA", 68 | "WDAY", 69 | "WDC", 70 | "XLNX" 71 | ], 72 | "nyse": [ 73 | "ABBV", 74 | "ABT", 75 | "ACN", 76 | "ADM", 77 | "AEP", 78 | "AIG", 79 | "ALL", 80 | "AMT", 81 | "ANTM", 82 | "APD", 83 | "AXP", 84 | "BA", 85 | "BAC", 86 | "BAX", 87 | "BBY", 88 | "BDX", 89 | "BK", 90 | "BLK", 91 | "BMY", 92 | "BRKb", 93 | "BSX", 94 | "C", 95 | "CAH", 96 | "CAT", 97 | "CB", 98 | "CCI", 99 | "CCL", 100 | "CI", 101 | "CL", 102 | "CLX", 103 | "CMA", 104 | "CMI", 105 | "CNC", 106 | "COF", 107 | "COP", 108 | "CRM", 109 | "CVS", 110 | "CVX", 111 | "D", 112 | "DAL", 113 | "DD", 114 | "DE", 115 | "DFS", 116 | "DG", 117 | "DHI", 118 | "DHR", 119 | "DIS", 120 | "DOW", 121 | "DUK", 122 | "EL", 123 | "EMR", 124 | "EOG", 125 | "ETN", 126 | "EW", 127 | "EXC", 128 | "FDX", 129 | "FIS", 130 | "FTV", 131 | "GD", 132 | "GE", 133 | "GIS", 134 | "GLW", 135 | "GM", 136 | "GS", 137 | "GWW", 138 | "HAL", 139 | "HCA", 140 | "HD", 141 | "HES", 142 | "HLT", 143 | "HON", 144 | "HPE", 145 | "HPQ", 146 | "HUM", 147 | "IBM", 148 | "ICE", 149 | "ITW", 150 | "JCI", 151 | "JNJ", 152 | "JPM", 153 | "KDP", 154 | "KEY", 155 | "KMB", 156 | "KMI", 157 | "KO", 158 | "KR", 159 | "LEN", 160 | "LLY", 161 | "LMT", 162 | "LOW", 163 | "LUV", 164 | "LVS", 165 | "LYB", 166 | "MA", 167 | "MCD", 168 | "MCK", 169 | "MDT", 170 | "MET", 171 | "MMC", 172 | "MMM", 173 | "MO", 174 | "MPC", 175 | "MRK", 176 | "MS", 177 | "NEE", 178 | "NEM", 179 | "NKE", 180 | "NOC", 181 | "NSC", 182 | "OKE", 183 | "OMC", 184 | "ORCL", 185 | "OXY", 186 | "PANW", 187 | "PFE", 188 | "PG", 189 | "PGR", 190 | "PH", 191 | "PLD", 192 | "PM", 193 | "PNC", 194 | "PPG", 195 | "PRU", 196 | "PSA", 197 | "PXD", 198 | "RCL", 199 | "RF", 200 | "ROK", 201 | "SCHW", 202 | "SHW", 203 | "SLB", 204 | "SO", 205 | "SPG", 206 | "SPGI", 207 | "SRE", 208 | "STT", 209 | "STZ", 210 | "SWK", 211 | "SYF", 212 | "SYK", 213 | "SYY", 214 | "T", 215 | "TGT", 216 | "TJX", 217 | "TMO", 218 | "TRV", 219 | "TSN", 220 | "TWTR", 221 | "UAL", 222 | "UNH", 223 | "UNP", 224 | "UPS", 225 | "USB", 226 | "V", 227 | "VFC", 228 | "VLO", 229 | "VMW", 230 | "VZ", 231 | "WFC", 232 | "WM", 233 | "WMB", 234 | "WMT", 235 | "XOM", 236 | "ZTS" 237 | ], 238 | "commodities": [ 239 | "XAG_USD", 240 | "XAU_USD", 241 | "XNG_USD**", 242 | "XTI_USD**" 243 | ], 244 | "fx": [ 245 | "AUD_CAD", 246 | "AUD_CHF", 247 | "AUD_JPY", 248 | "AUD_NZD", 249 | "AUD_USD", 250 | "CAD_CHF", 251 | "CAD_JPY", 252 | "CHF_JPY", 253 | "EUR_AUD", 254 | "EUR_CAD", 255 | "EUR_CHF", 256 | "EUR_GBP", 257 | "EUR_JPY", 258 | "EUR_MXN", 259 | "EUR_NOK", 260 | "EUR_NZD", 261 | "EUR_SEK", 262 | "EUR_TRY", 263 | "EUR_USD", 264 | "GBP_AUD", 265 | "GBP_CAD", 266 | "GBP_CHF", 267 | "GBP_JPY", 268 | "GBP_MXN", 269 | "GBP_NOK", 270 | "GBP_NZD", 271 | "GBP_SEK", 272 | "GBP_TRY", 273 | "GBP_USD", 274 | "NZD_CAD", 275 | "NZD_CHF", 276 | "NZD_JPY", 277 | "NZD_USD", 278 | "USD_CAD", 279 | "USD_CHF", 280 | "USD_JPY", 281 | "USD_MXN", 282 | "USD_NOK", 283 | "USD_SEK", 284 | "USD_SGD", 285 | "USD_TRY" 286 | ], 287 | "indices": [ 288 | "AUS200", 289 | "FCHI40", 290 | "GDAXI", 291 | "J225", 292 | "NDX", 293 | "SPA35", 294 | "SPX500", 295 | "STOXX50E", 296 | "UK100", 297 | "WS30" 298 | ], 299 | "fx_codes": [ 300 | "TRY", 301 | "CHF", 302 | "EUR", 303 | "AUD", 304 | "SEK", 305 | "GBP", 306 | "MXN", 307 | "NOK", 308 | "JPY", 309 | "NZD", 310 | "USD", 311 | "CAD", 312 | "SGD" 313 | ] 314 | } -------------------------------------------------------------------------------- /brokerage/darwinex/darwinex.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from brokerage.darwinex.TradeClient import TradeClient 4 | from brokerage.darwinex.ServiceClient import ServiceClient 5 | 6 | #note that the contract specifications are different from oanda - each contract has different sizing 7 | #for FX; 100000 8 | #etc... 9 | class Darwinex(): 10 | 11 | def __init__(self, brokerage_config=None, auth_config=None): 12 | self.brokerage_config = brokerage_config 13 | self.auth_config=auth_config 14 | self.trade_client = None 15 | self.service_client = None 16 | 17 | def get_service_client(self): 18 | if self.service_client is None: 19 | self.service_client = ServiceClient(brokerage_config=self.brokerage_config) 20 | return self.service_client 21 | 22 | 23 | def get_trade_client(self): 24 | if self.trade_client is None: 25 | self.trade_client = TradeClient( 26 | brokerage_config=self.brokerage_config, 27 | auth_config=self.auth_config, 28 | service_client=self.get_service_client() 29 | ) 30 | return self.trade_client -------------------------------------------------------------------------------- /brokerage/darwinex/scraper.py: -------------------------------------------------------------------------------- 1 | #we can scrape the html Darwinex site for assets tradable 2 | 3 | import json 4 | from bs4 import BeautifulSoup 5 | 6 | 7 | assets = {} 8 | #it seems that our scraping had issues as the nasdaq and nyse content is the same 9 | with open("./htmls/nasdaq.txt") as f: 10 | contents = f.read() 11 | soup = BeautifulSoup(contents, "html.parser") 12 | stocks = soup.find(id="stocksUsd-content") 13 | rows = stocks.find_all("tr") 14 | codes = [] 15 | for r in rows: 16 | code = str(r).split("")[0].split("")[1] #there are better ways to get this, but this works 17 | codes.append(code) 18 | assets["nasdaq"] = codes 19 | 20 | with open("./htmls/nyse.txt") as f: 21 | contents = f.read() 22 | soup = BeautifulSoup(contents, "html.parser") 23 | stocks = soup.find(id="stocksUsd-content") 24 | rows = stocks.find_all("tr") 25 | codes = [] 26 | for r in rows: 27 | code = str(r).split("")[0].split("")[1] #there are better ways to get this, but this works 28 | codes.append(code) 29 | assets["nyse"] = codes 30 | 31 | with open("./htmls/commodities.txt") as f: 32 | contents = f.read() 33 | soup = BeautifulSoup(contents, "html.parser") 34 | items = soup.find(id="commodities-content") 35 | rows = items.find_all("tr") 36 | codes = [] 37 | for r in rows: 38 | code = str(r).split("")[0].split("")[1] #there are better ways to get this, but this works 39 | codes.append(code) 40 | assets["commodities"] = codes 41 | 42 | with open("./htmls/fx.txt") as f: 43 | contents = f.read() 44 | soup = BeautifulSoup(contents, "html.parser") 45 | items = soup.find(id="forex-content") 46 | rows = items.find_all("tr") 47 | codes = [] 48 | for r in rows: 49 | code = str(r).split("")[0].split("")[1] #there are better ways to get this, but this works 50 | codes.append(code) 51 | assets["fx"] = codes 52 | 53 | with open("./htmls/indices.txt") as f: 54 | contents = f.read() 55 | soup = BeautifulSoup(contents, "html.parser") 56 | items = soup.find(id="indices-content") 57 | rows = items.find_all("tr") 58 | codes = [] 59 | for r in rows: 60 | code = str(r).split("")[0].split("")[1] #there are better ways to get this, but this works 61 | codes.append(code) 62 | assets["indices"] = codes 63 | 64 | fx_codes = [] 65 | for fx in assets["fx"]: 66 | fx_codes.append(fx[:3]) 67 | fx_codes.append(fx[3:]) 68 | fx_codes = list(set(fx_codes)) 69 | assets["fx_codes"] = fx_codes 70 | 71 | commodity_lables = [] 72 | for com in assets["commodities"]: 73 | label = com[:3] + "_" + com[3:] 74 | commodity_lables.append(label) 75 | 76 | fx_lables = [] 77 | for fx in assets["fx"]: 78 | label = fx[:3] + "_" + fx[3:] 79 | fx_lables.append(label) 80 | 81 | assets["commodities"] = commodity_lables 82 | assets["fx"] = fx_lables 83 | 84 | print(json.dumps(assets, indent=4)) 85 | 86 | #lets try to write this to a json file and set our dwx_config 87 | with open("assets.json", "w") as f: 88 | json.dump(assets, f, indent=4) -------------------------------------------------------------------------------- /brokerage/oanda/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/brokerage/oanda/.DS_Store -------------------------------------------------------------------------------- /brokerage/oanda/ServiceClient.py: -------------------------------------------------------------------------------- 1 | #aids in the order logic and helps integrate the brokerage into the system, no external dependency 2 | 3 | 4 | class ServiceClient(): 5 | 6 | def __init__(self, brokerage_config=None): 7 | self.brokerage_config = brokerage_config 8 | 9 | #lets implement some API interface that our TradeClient would use, and later we will see how they become useful 10 | 11 | def get_size_config(self, inst): 12 | order_min_contracts = 1 #minimum size of order 13 | contract_size = 1 #size in units of a contract 14 | return order_min_contracts, contract_size 15 | 16 | def get_order_specs(self, inst, units, current_contracts): 17 | #this is an internal `order` object that is passed around different components of the trading system 18 | #it is the `settings` of an order item, that all brokerages should implement to meet internal needs 19 | order_min_contracts, contract_size = self.get_size_config(inst) 20 | order_min_units = self.contracts_to_units(label=inst, contracts=order_min_contracts) 21 | optimal_min_order = units / order_min_units 22 | rounded_min_order = round(optimal_min_order) 23 | specs = { 24 | "instrument": inst, 25 | "scaled_units": units, 26 | "contract_size": contract_size, 27 | "order_min_contracts": order_min_contracts, 28 | "order_min_units": order_min_units, 29 | "optimal_contracts": optimal_min_order * order_min_contracts, 30 | "rounded_contracts": rounded_min_order * order_min_contracts, 31 | "current_contracts": current_contracts, 32 | "current_units": self.contracts_to_units(inst, current_contracts) 33 | } 34 | return specs 35 | 36 | def contracts_to_units(self, label, contracts): 37 | order_min_contracts, contract_size = self.get_size_config(label) 38 | return contracts * contract_size 39 | 40 | def units_to_contracts(self, label, units): 41 | #these are conversions between contract and unit sizing, for instance how many units are there in a micro contract, a mini contract etc? 42 | #these depend on the brokerage specifications! 43 | order_min_contracts, contract_size = self.get_size_config(label) 44 | return units / contract_size 45 | 46 | 47 | def is_inertia_override(self, percent_change): 48 | return percent_change > 0.05 #positional inertia to prevent too frequent trading 49 | 50 | def code_to_label_nomenclature(self, code): 51 | #these are external to internal conversions between instrument naming 52 | #for instance a EUR/USD contract can be: EUR_USD, EUR/USD, EUR;USD etc etc. let code be the brokerage code, and the label be the internal name 53 | return code 54 | 55 | def label_to_code_nomenclature(self, label): 56 | return label 57 | -------------------------------------------------------------------------------- /brokerage/oanda/TradeClient.py: -------------------------------------------------------------------------------- 1 | #interacts with the oandapyV20 api to make, update, delete and read orders 2 | #the documentation and code samples give us all the info we need! https://readthedocs.org/projects/oanda-api-v20/downloads/pdf/latest/ 3 | 4 | import json 5 | import pandas as pd 6 | import datetime 7 | import oandapyV20 8 | import oandapyV20.endpoints.orders as orders 9 | import oandapyV20.endpoints.trades as trades 10 | import oandapyV20.endpoints.pricing as pricing 11 | import oandapyV20.endpoints.accounts as accounts 12 | import oandapyV20.endpoints.positions as positions 13 | import oandapyV20.endpoints.instruments as instruments 14 | 15 | from collections import defaultdict 16 | 17 | class TradeClient(): 18 | 19 | def __init__(self, brokerage_config=None, auth_config=None, service_client=None): 20 | self.id = auth_config["oan_acc_id"] 21 | self.token = auth_config["oan_token"] 22 | self.env = auth_config["oan_env"] 23 | self.client = oandapyV20.API(access_token=self.token, environment=self.env) 24 | 25 | """ 26 | We are interested in getting 27 | 1. Capital 28 | 2. Positions 29 | 3. Submit Orders 30 | 4. Get OHLCV data etc 31 | """ 32 | 33 | def get_account_details(self): 34 | try: 35 | return self.client.request(accounts.AccountDetails(self.id))["account"] 36 | except Exception as err: 37 | print(err) 38 | 39 | def get_account_summary(self): 40 | try: 41 | return self.client.request(accounts.AccountSummary(self.id))["account"] 42 | except Exception as err: 43 | print(err) 44 | #do your error handling 45 | 46 | def get_account_instruments(self): 47 | #Get the list of tradable instruments for the given Account. The list of tradeable instruments is dependent on the regulatory division that the Account is located in 48 | #we can get financing rates for instruments here , etc 49 | try: 50 | r = self.client.request(accounts.AccountInstruments(accountID=self.id))["instruments"] 51 | instruments = {} 52 | currencies, cfds, metals = [], [], [] 53 | tags = defaultdict(list) 54 | for inst in r: 55 | #suppose we want to also store their tags 56 | inst_name = inst["name"] 57 | type = inst["type"] 58 | tag_name = inst["tags"][0]["name"] 59 | tags[tag_name].append(inst_name) 60 | instruments[inst_name] = { 61 | "type": type, #and other things you want to store, such as precision, marginRate etc 62 | "tag": inst["tags"][0]["name"] 63 | } 64 | if type == "CFD": 65 | cfds.append(inst_name) 66 | elif type == "CURRENCY": 67 | currencies.append(inst_name) 68 | elif type == "METAL": 69 | metals.append(inst_name) 70 | else: 71 | print("unknown type", inst_name) 72 | exit() 73 | 74 | return instruments, currencies, cfds, metals, tags 75 | except Exception as err: 76 | print(err) 77 | 78 | def get_account_capital(self): 79 | try: 80 | return float(self.get_account_summary()["NAV"]) 81 | except Exception as err: 82 | pass 83 | 84 | #we can try to enter some positions or trades to see what the return result looks like 85 | #we see that the Oanda brokerage automatically performs netting of positions 86 | #we bought 30 EUR_USD units, sold 6, and we have 24 units of open positions 87 | #do note that this is not the same for every brokerage. In some cases, brokerages allow two open trades of opposing direction without netting 88 | #this would cause the txn fees to increase! 89 | def get_account_positions(self): 90 | positions_data = self.get_account_details()["positions"] 91 | positions = {} 92 | for entry in positions_data: 93 | instrument = entry["instrument"] 94 | long_pos = float(entry["long"]["units"]) 95 | short_pos = float(entry["short"]["units"]) 96 | net_pos = long_pos + short_pos 97 | if net_pos != 0: 98 | positions[instrument] = net_pos 99 | return positions 100 | 101 | def get_account_trades(self): 102 | try: 103 | trade_data = self.client.request(trades.OpenTrades(accountID=self.id)) 104 | return trade_data 105 | except Exception as err: 106 | pass 107 | 108 | def format_date(self, series): 109 | #series in the form :: 2021-09-21T21:00:00.000000000Z 110 | ddmmyy = series.split("T")[0].split("-") 111 | return datetime.date(int(ddmmyy[0]), int(ddmmyy[1]), int(ddmmyy[2])) 112 | 113 | def get_ohlcv(self, instrument, count, granularity): 114 | try: 115 | params = {"count": count, "granularity": granularity} 116 | candles = instruments.InstrumentsCandles(instrument=instrument, params=params) 117 | self.client.request(candles) 118 | ohlcv_dict = candles.response["candles"] 119 | ohlcv = pd.DataFrame(ohlcv_dict) 120 | ohlcv = ohlcv[ohlcv["complete"]] 121 | ohlcv_df = ohlcv["mid"].dropna().apply(pd.Series) 122 | ohlcv_df["volume"] = ohlcv["volume"] 123 | ohlcv_df.index = ohlcv["time"] 124 | ohlcv_df = ohlcv_df.apply(pd.to_numeric) 125 | ohlcv_df.reset_index(inplace=True) #once again we want to format the date and columns in the same way as we did for the extend_dataframe function for sp500 dataset 126 | ohlcv_df.columns = ["date", "open", "high", "low", "close", "volume"] 127 | ohlcv_df["date"] = ohlcv_df["date"].apply(lambda x: self.format_date(x)) #this is the format that yahoo finance API gave us, and we just need to add identifiers! 128 | return ohlcv_df 129 | except Exception as err: 130 | print(err) #do some error handling 131 | 132 | def market_order(self, inst, order_config={}): 133 | #lets try to make a fill or kill market order - read the documentation for the order types and what they mean 134 | contract_change = order_config["rounded_contracts"] - order_config["current_contracts"] 135 | order_data = { 136 | "order": { 137 | "price": "", #market order is liqudity taking 138 | "timeInForce": "FOK", 139 | "instrument": inst, 140 | "units": str(contract_change), 141 | "type": "MARKET", 142 | "positionFill": "DEFAULT" 143 | } 144 | } 145 | print(json.dumps(order_config, indent=4)) 146 | print(json.dumps(order_data, indent=4)) 147 | r = orders.OrderCreate(accountID=self.id, data=order_data) 148 | self.client.request(r) 149 | return r.response 150 | 151 | #we need to implement these functionalities to have a `successful` TradeClient. This is what is `promised` to be implemented to other components of the trading system, 152 | #no matter what brokerage is used! 153 | #lets now implement these wrapper functions 154 | 155 | -------------------------------------------------------------------------------- /brokerage/oanda/oanda.py: -------------------------------------------------------------------------------- 1 | #I already created a demo oanda account. pip install oandapyV20, and generate your own API key 2 | #READ the documentation and code samples! We are choosing the REST API option instead of the streaming option. 3 | # oanda_id: 101-003-13732651-006 4 | # oanda_key: 6320bb8b1dd427ff7b5c6dd31f00675e-05e3c53f0a74851c18d25b929510b2cd 5 | 6 | from brokerage.oanda.TradeClient import TradeClient 7 | from brokerage.oanda.ServiceClient import ServiceClient 8 | 9 | class Oanda(): 10 | 11 | def __init__(self, brokerage_config=None, auth_config=None): 12 | self.service_client = ServiceClient(brokerage_config=brokerage_config) 13 | self.trade_client = TradeClient(auth_config=auth_config) 14 | #lets create a service class and trade class for Oanda 15 | 16 | def get_service_client(self): 17 | return self.service_client 18 | 19 | def get_trade_client(self): 20 | return self.trade_client -------------------------------------------------------------------------------- /config/auth_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "oan_acc_id": "101-003-13732651-006", 3 | "oan_token": "6320bb8b1dd427ff7b5c6dd31f00675e-05e3c53f0a74851c18d25b929510b2cd", 4 | "oan_env": "practice" 5 | } -------------------------------------------------------------------------------- /config/crypto_config.py: -------------------------------------------------------------------------------- 1 | 2 | ########SETTINGS################ 3 | long_amount = 7800 4 | short_amount = long_amount * 0.6 5 | long_nums, short_nums = 8, 0 6 | ################################ 7 | 8 | long_leverage, short_leverage = 4, 2 9 | long_collateral, short_collateral = 0, 0 10 | long_collateral = int(long_amount / long_leverage) 11 | short_collateral = int(short_amount / short_leverage) 12 | 13 | BUY_PARAMS = { 14 | "side": "BUY", 15 | "leverage": long_leverage, 16 | "collateral": long_collateral, 17 | } 18 | 19 | SELL_PARAMS = { 20 | "side": "SELL", 21 | "leverage": short_leverage, 22 | "collateral": short_collateral, 23 | } 24 | 25 | if __name__ == "__main__": 26 | print (BUY_PARAMS) 27 | print (SELL_PARAMS) -------------------------------------------------------------------------------- /config/dwx_config.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "order_min_contracts": { 4 | "fx": 0.01, 5 | "equities": 1, 6 | 7 | "XAG_USD": 0.01, 8 | "XNG_USD": 0.10, 9 | "XAU_USD": 0.01, 10 | "XTI_USD": 0.01 11 | }, 12 | 13 | "contract_size": { 14 | "fx": 100000, 15 | "equities": 1, 16 | 17 | "XAG_USD": 5000, 18 | "XNG_USD": 10000, 19 | "XAU_USD": 100, 20 | "XTI_USD": 1000 21 | }, 22 | 23 | "equities": [ 24 | "AAL", 25 | "AAPL", 26 | "ADBE", 27 | "ADI", 28 | "ADP", 29 | "ADSK", 30 | "AMAT", 31 | "AMD", 32 | "AMGN", 33 | "AMZN", 34 | "ATVI", 35 | "AVGO", 36 | "BIIB", 37 | "BKNG", 38 | "CHTR", 39 | "CMCSA", 40 | "CME", 41 | "COST", 42 | "CSCO", 43 | "CSX", 44 | "CTSH", 45 | "DLTR", 46 | "EA", 47 | "EBAY", 48 | "EXPE", 49 | "FAST", 50 | "FB", 51 | "FISV", 52 | "FITB", 53 | "FOX", 54 | "FOXA", 55 | "C", 56 | "CAH", 57 | "CAT", 58 | "CB", 59 | "CCI", 60 | "CCL", 61 | "CI", 62 | "CL", 63 | "CLX", 64 | "CMA", 65 | "CMI", 66 | "CNC", 67 | "COF", 68 | "COP", 69 | "CRM", 70 | "CVS", 71 | "DHR", 72 | "DIS", 73 | "DOW", 74 | "DUK", 75 | "EL", 76 | "EMR", 77 | "EOG", 78 | "ETN", 79 | "EW", 80 | "EXC", 81 | "FDX", 82 | "FIS", 83 | "FTV", 84 | "GD", 85 | "GE", 86 | "GIS", 87 | "GLW", 88 | "GM", 89 | "GS", 90 | "GWW", 91 | "HAL", 92 | "HCA", 93 | "HD", 94 | "HES", 95 | "HLT", 96 | "HON", 97 | "HPE", 98 | "HPQ", 99 | "HUM", 100 | "IBM", 101 | "ICE", 102 | "ITW", 103 | "JCI", 104 | "LYB", 105 | "MA", 106 | "MCD", 107 | "MCK", 108 | "MDT", 109 | "MET", 110 | "MMC", 111 | "MMM", 112 | "MO", 113 | "MPC", 114 | "MRK", 115 | "MS", 116 | "NEE", 117 | "NEM", 118 | "NKE", 119 | "NOC", 120 | "NSC", 121 | "OKE", 122 | "OMC", 123 | "ORCL", 124 | "OXY", 125 | "PANW", 126 | "PFE", 127 | "PG", 128 | "PGR", 129 | "PH", 130 | "PLD", 131 | "PM", 132 | "PNC", 133 | "PPG", 134 | "PRU", 135 | "PSA", 136 | "PXD", 137 | "RCL", 138 | "RF", 139 | "ROK", 140 | "SCHW", 141 | "SHW", 142 | "SLB", 143 | "SO", 144 | "SPG", 145 | "SPGI", 146 | "SRE", 147 | "STT", 148 | "STZ", 149 | "SWK", 150 | "SYF", 151 | "SYK", 152 | "SYY", 153 | "T", 154 | "TGT", 155 | "TJX", 156 | "TMO", 157 | "WMT", 158 | "XOM", 159 | "ZTS" 160 | ], 161 | 162 | "commodities": [ 163 | "XAG_USD", 164 | "XAU_USD", 165 | "XNG_USD", 166 | "XTI_USD" 167 | ], 168 | 169 | "fx": [ 170 | "AUD_USD", 171 | "EUR_USD", 172 | "GBP_USD", 173 | "NZD_USD", 174 | "USD_CAD", 175 | "USD_CHF", 176 | "USD_JPY", 177 | "USD_MXN", 178 | "USD_NOK", 179 | "USD_SEK", 180 | "USD_SGD", 181 | "USD_TRY" 182 | ], 183 | 184 | "indices": [ 185 | ], 186 | 187 | "fx_codes": [ 188 | "TRY", 189 | "CHF", 190 | "EUR", 191 | "AUD", 192 | "SEK", 193 | "GBP", 194 | "MXN", 195 | "NOK", 196 | "JPY", 197 | "NZD", 198 | "USD", 199 | "CAD", 200 | "SGD" 201 | ] 202 | } -------------------------------------------------------------------------------- /config/oan_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": [ 3 | "LTC_USD", 4 | "BTC_USD", 5 | "ETH_USD", 6 | "BCH_USD" 7 | ], 8 | "indices": [ 9 | "HK33_HKD", 10 | "FR40_EUR", 11 | "IN50_USD", 12 | "JP225_USD", 13 | "CN50_USD", 14 | "EU50_EUR", 15 | "TWIX_USD", 16 | "US2000_USD", 17 | "UK100_GBP", 18 | "SPX500_USD", 19 | "JP225Y_JPY", 20 | "ESPIX_EUR", 21 | "NAS100_USD", 22 | "NL25_EUR", 23 | "SG30_SGD", 24 | "AU200_AUD", 25 | "CHINAH_HKD", 26 | "CH20_CHF", 27 | "US30_USD", 28 | "DE30_EUR" 29 | ], 30 | "fx": [ 31 | "USD_MXN", 32 | "GBP_USD", 33 | "USD_THB", 34 | "USD_ZAR", 35 | "USD_SEK", 36 | "USD_CHF", 37 | "USD_TRY", 38 | "USD_JPY", 39 | "USD_CZK", 40 | "USD_NOK", 41 | "USD_DKK", 42 | "USD_HKD", 43 | "NZD_USD", 44 | "USD_CNH", 45 | "USD_SGD", 46 | "USD_CAD", 47 | "USD_INR", 48 | "USD_HUF", 49 | "AUD_USD", 50 | "EUR_USD", 51 | "USD_PLN" 52 | ], 53 | 54 | "metals": [ 55 | "XPD_USD", 56 | "XAU_USD", 57 | "XPT_USD", 58 | "XAG_USD" 59 | ], 60 | 61 | "commodities": [ 62 | "BCO_USD", 63 | "NATGAS_USD", 64 | "XCU_USD", 65 | "WTICO_USD", 66 | "SUGAR_USD", 67 | "CORN_USD", 68 | "WHEAT_USD", 69 | "SOYBN_USD" 70 | ], 71 | 72 | "bonds": [ 73 | "DE10YB_EUR", 74 | "USB02Y_USD", 75 | "USB05Y_USD", 76 | "USB10Y_USD", 77 | "UK10YB_GBP", 78 | "USB30Y_USD" 79 | ], 80 | 81 | "fx_codes": [ 82 | "HKD", 83 | "HUF", 84 | "GBP", 85 | "CNH", 86 | "NOK", 87 | "EUR", 88 | "TRY", 89 | "SGD", 90 | "CZK", 91 | "USD", 92 | "ZAR", 93 | "INR", 94 | "SEK", 95 | "JPY", 96 | "CAD", 97 | "NZD", 98 | "THB", 99 | "PLN", 100 | "AUD", 101 | "CHF", 102 | "DKK", 103 | "MXN" 104 | ] 105 | } -------------------------------------------------------------------------------- /config/portfolio_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "brokerage": "oan", 3 | "use_disk": false, 4 | "brokerage_config": { 5 | "dwx": "dwx_config.json", 6 | "oan": "oan_config.json" 7 | }, 8 | "database": { 9 | "dwx": "dwx_ohlcv.xlsx", 10 | "oan": "oan_ohlcv.xlsx" 11 | }, 12 | 13 | "order_enabled": false, 14 | "sim_years" : 3, 15 | "vol_target" : 0.20, 16 | 17 | "instruments_config": { 18 | "lbmom": { 19 | "oan": "./subsystems/LBMOM/oan_config.json", 20 | "dwx": "./subsystems/LBMOM/dwx_config.json" 21 | }, 22 | "lsmom": { 23 | "oan": "./subsystems/LSMOM/oan_config.json", 24 | "dwx": "./subsystems/LSMOM/dwx_config.json" 25 | }, 26 | "skprm": { 27 | "oan": "./subsystems/SKPRM/oan_config.json" 28 | } 29 | }, 30 | 31 | "subsystems": { 32 | "oan": { 33 | "lbmom": 0.40, 34 | "lsmom": 0.40, 35 | "skprm": 0.20 36 | }, 37 | "dwx": { 38 | "lbmom": 0.50, 39 | "lsmom": 0.50 40 | } 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /crypto_momentum.py: -------------------------------------------------------------------------------- 1 | import json 2 | import datetime 3 | import pandas as pd 4 | 5 | from dateutil.relativedelta import relativedelta 6 | import quantlib.crypto_data_utils as crypto_du 7 | from brokerage.binance.TradeClient import TradeClient 8 | 9 | import config.crypto_config as conf 10 | 11 | import warnings 12 | warnings.filterwarnings("ignore") 13 | 14 | def prepare_data(): 15 | """ 16 | Get Data, update database 17 | 18 | Return: the extended historical data, all instruments 19 | """ 20 | 21 | db_file = "crypto_ohlv_4h.xlsx" 22 | db_file_path = f"./Data/{db_file}" 23 | database_df = pd.read_excel(db_file_path).set_index("open_time") 24 | 25 | new_df, instruments = crypto_du.get_crypto_futures_df(interval="4h", limit=100) 26 | merge_df = pd.concat([database_df, new_df]) 27 | merge_df = merge_df[~merge_df.index.duplicated(keep='last')].sort_index() 28 | merge_df.to_excel(db_file_path) 29 | # Historical_data would include everything till now, also the current not finished kline 30 | historical_data = crypto_du.extend_dataframe(traded=instruments, df=merge_df, interval="4h") 31 | historical_data.to_excel("crypto_historical_4h.xlsx") 32 | 33 | return historical_data, instruments 34 | 35 | def generate_signal(historical_data, instruments): 36 | """ 37 | Generate signals 38 | """ 39 | df = historical_data.copy() 40 | LOOK_BACK = 40 41 | LOOK_AHEAD = 20 42 | K = 20 43 | IGNORES = 5 # We do not want to count the closest momentum for possible reversion 44 | 45 | ret_cols = [] 46 | SHIFT_UNITS = LOOK_BACK + IGNORES 47 | for inst in instruments: 48 | if df.iloc[-SHIFT_UNITS][f"{inst} active"] == False: 49 | print ("Not active symbols: ", inst) 50 | continue 51 | ret_col_name = "{} {} ret".format(inst, LOOK_BACK) 52 | ret_cols.append(ret_col_name) 53 | df[ret_col_name] = df["{} close".format(inst)].shift(IGNORES) / df["{} close".format(inst)].shift(SHIFT_UNITS) - 1 54 | 55 | last = df[ret_cols].tail(1).reset_index(drop=True) 56 | for col in last.columns: 57 | if last.loc[0, col] == 0: ret_cols.remove(col) 58 | rank = pd.qcut(last.loc[0, ret_cols], K, labels=False) 59 | 60 | # Based on rank generate symbols to be longed and symbols to be shorted 61 | long_list, short_list = [], [] 62 | for col in ret_cols: 63 | symbol = col.split(" ")[0] 64 | if rank[col] == 0: short_list.append(symbol) 65 | elif rank[col] == K-1: long_list.append(symbol) 66 | 67 | print ("Long list: ", long_list) 68 | print ("Short list: ", short_list) 69 | return long_list, short_list 70 | 71 | def execute_orders(long_list, short_list, test=True): 72 | """ 73 | Execute orders, if test, no orders will be made 74 | """ 75 | client = TradeClient() 76 | curr_positions = client.get_account_positions() 77 | if test: 78 | print (curr_positions) 79 | return 80 | 81 | # Close positions 82 | for symbol, details in curr_positions.items(): 83 | position_amount = details['positionAmt'] 84 | if symbol in long_list and position_amount > 0: 85 | continue 86 | if symbol in short_list and position_amount < 0: 87 | continue 88 | client.close_positon(symbol, details) 89 | 90 | # Open positons 91 | curr_positions = client.get_account_positions() 92 | 93 | for symbol in long_list: 94 | if symbol not in curr_positions: 95 | client.open_position(symbol, conf.BUY_PARAMS) 96 | 97 | for symbol in short_list: 98 | if symbol not in curr_positions: 99 | client.open_position(symbol, conf.SELL_PARAMS) 100 | 101 | print ("Orders have been placed!") 102 | 103 | 104 | def main(use_disk=False, test=True): 105 | if not use_disk: 106 | historical_data, instruments = prepare_data() 107 | else: 108 | historical_data = pd.read_excel("./crypto_historical_4h.xlsx", engine="openpyxl", index_col='open_time') 109 | instruments = crypto_du.get_symbols_from_df(historical_data) 110 | 111 | long_list, short_list = generate_signal(historical_data, instruments) 112 | execute_orders(long_list, short_list, test) 113 | 114 | if __name__ == "__main__": 115 | print ("Working!") 116 | main(use_disk=True, test=False) 117 | -------------------------------------------------------------------------------- /diagnostics/HANGUKQUANT/dwx_leverage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/HANGUKQUANT/dwx_leverage.png -------------------------------------------------------------------------------- /diagnostics/HANGUKQUANT/dwx_scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/HANGUKQUANT/dwx_scatter.png -------------------------------------------------------------------------------- /diagnostics/HANGUKQUANT/dwx_weights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/HANGUKQUANT/dwx_weights.png -------------------------------------------------------------------------------- /diagnostics/HANGUKQUANT/oan_leverage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/HANGUKQUANT/oan_leverage.png -------------------------------------------------------------------------------- /diagnostics/HANGUKQUANT/oan_scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/HANGUKQUANT/oan_scatter.png -------------------------------------------------------------------------------- /diagnostics/HANGUKQUANT/oan_weights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/HANGUKQUANT/oan_weights.png -------------------------------------------------------------------------------- /diagnostics/LBMOM/binance_leverage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LBMOM/binance_leverage.png -------------------------------------------------------------------------------- /diagnostics/LBMOM/binance_scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LBMOM/binance_scatter.png -------------------------------------------------------------------------------- /diagnostics/LBMOM/binance_weights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LBMOM/binance_weights.png -------------------------------------------------------------------------------- /diagnostics/LBMOM/dwx_leverage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LBMOM/dwx_leverage.png -------------------------------------------------------------------------------- /diagnostics/LBMOM/dwx_scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LBMOM/dwx_scatter.png -------------------------------------------------------------------------------- /diagnostics/LBMOM/dwx_weights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LBMOM/dwx_weights.png -------------------------------------------------------------------------------- /diagnostics/LBMOM/oan_leverage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LBMOM/oan_leverage.png -------------------------------------------------------------------------------- /diagnostics/LBMOM/oan_scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LBMOM/oan_scatter.png -------------------------------------------------------------------------------- /diagnostics/LBMOM/oan_weights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LBMOM/oan_weights.png -------------------------------------------------------------------------------- /diagnostics/LSMOM/dwx_leverage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LSMOM/dwx_leverage.png -------------------------------------------------------------------------------- /diagnostics/LSMOM/dwx_scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LSMOM/dwx_scatter.png -------------------------------------------------------------------------------- /diagnostics/LSMOM/dwx_weights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LSMOM/dwx_weights.png -------------------------------------------------------------------------------- /diagnostics/LSMOM/oan_leverage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LSMOM/oan_leverage.png -------------------------------------------------------------------------------- /diagnostics/LSMOM/oan_scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LSMOM/oan_scatter.png -------------------------------------------------------------------------------- /diagnostics/LSMOM/oan_weights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/LSMOM/oan_weights.png -------------------------------------------------------------------------------- /diagnostics/SKPRM/oan_leverage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/SKPRM/oan_leverage.png -------------------------------------------------------------------------------- /diagnostics/SKPRM/oan_scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/SKPRM/oan_scatter.png -------------------------------------------------------------------------------- /diagnostics/SKPRM/oan_weights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/diagnostics/SKPRM/oan_weights.png -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-vendored 2 | *.py linguist-vendored=false 3 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, Darwinex Labs 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/README.md: -------------------------------------------------------------------------------- 1 | This project incorporates functionality authored by Ding Li (GitHub: https://github.com/dingmaotu), who has kindly licensed his work under the Apache 2.0 license. 2 | 3 | We acknowledge copyright as per the terms of the license, the following repositories serving as mandatory dependencies for this project: 4 | 5 | 1. https://github.com/dingmaotu/mql-zmq 6 | 7 | 1. https://github.com/dingmaotu/mql4-lib 8 | 9 | Thank you Ding for your amazing open source contribution to this space! 10 | 11 | Sincerely,
12 | The Darwinex Labs Team
13 | www.darwinex.com 14 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/dependencies/mql-zmq-master.zip -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/ALIPAY.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/ALIPAY.JPG -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Include/Mql/Lang/Error.mqh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Include/Mql/Lang/Error.mqh -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Include/Mql/Lang/Mql.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Module: Lang/Mql.mqh | 3 | //| This file is part of the mql4-lib project: | 4 | //| https://github.com/dingmaotu/mql4-lib | 5 | //| | 6 | //| Copyright 2017 Li Ding | 7 | //| | 8 | //| Licensed under the Apache License, Version 2.0 (the "License"); | 9 | //| you may not use this file except in compliance with the License. | 10 | //| You may obtain a copy of the License at | 11 | //| | 12 | //| http://www.apache.org/licenses/LICENSE-2.0 | 13 | //| | 14 | //| Unless required by applicable law or agreed to in writing, | 15 | //| software distributed under the License is distributed on an | 16 | //| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, | 17 | //| either express or implied. | 18 | //| See the License for the specific language governing permissions | 19 | //| and limitations under the License. | 20 | //+------------------------------------------------------------------+ 21 | #property strict 22 | #include "Error.mqh" 23 | //+------------------------------------------------------------------+ 24 | //| Mql language specific methods | 25 | //+------------------------------------------------------------------+ 26 | class Mql 27 | { 28 | public: 29 | static int getLastError() {return GetLastError();} 30 | static string getErrorMessage(int errorCode) {return GetErrorDescription(errorCode);} 31 | 32 | //--- Prefer global DoubleToString function 33 | static string doubleToString(double value,int precision) {return DoubleToString(value,precision);} 34 | //--- Adapted from stdlib.mq4 by using `StringSetCharacter` instead of `StringSetChar` 35 | static string integerToHexString(int value) 36 | { 37 | static const string digits="0123456789ABCDEF"; 38 | string hex="00000000"; 39 | int digit,shift=28; 40 | for(int i=0; i<8; i++) 41 | { 42 | digit=(value>>shift)&0x0F; 43 | StringSetCharacter(hex,i,digits[digit]); 44 | shift-=4; 45 | } 46 | return(hex); 47 | } 48 | //--- Prefer Canvas/Canvas.mqh XRGB 49 | static int rgb(int r,int g,int b) {return int(0xFF000000|(uchar(r)<<16)|(uchar(g)<<8)|uchar(b));} 50 | 51 | //--- Prefer Lang/Number.mqh Double::IsEqual 52 | static bool isEqual(double a,double b) {return NormalizeDouble(a-b,8)==0;} 53 | 54 | static bool isStopped() {return IsStopped();} 55 | 56 | static int getCodePage() {return MQLInfoInteger(MQL_CODEPAGE);} 57 | static ENUM_PROGRAM_TYPE getProgramType() {return(ENUM_PROGRAM_TYPE)MQLInfoInteger(MQL_PROGRAM_TYPE);} 58 | static bool isScript() {return Mql::getProgramType()==PROGRAM_SCRIPT;} 59 | static bool isExpert() {return Mql::getProgramType()==PROGRAM_EXPERT;} 60 | static bool isIndicator() {return Mql::getProgramType()==PROGRAM_INDICATOR;} 61 | static bool isDllAllowed() {return MQLInfoInteger(MQL_DLLS_ALLOWED)!=0;} 62 | static bool isTradeAllowed() {return MQLInfoInteger(MQL_TRADE_ALLOWED)!=0;} 63 | static bool isSignalsAllowed() {return MQLInfoInteger(MQL_SIGNALS_ALLOWED)!=0;} 64 | static bool isDebug() {return MQLInfoInteger(MQL_DEBUG)!=0;} 65 | static bool isProfiling() {return MQLInfoInteger(MQL_PROFILER)!=0;} 66 | static bool isTesting() {return MQLInfoInteger(MQL_TESTER)!=0;} 67 | static bool isOptimizing() {return MQLInfoInteger(MQL_OPTIMIZATION)!=0;} 68 | static bool isVisual() {return MQLInfoInteger(MQL_VISUAL_MODE)!=0;} 69 | static bool isFrameMode() {return MQLInfoInteger(MQL_FRAME_MODE)!=0;} 70 | static ENUM_LICENSE_TYPE getLicenseType() {return(ENUM_LICENSE_TYPE)MQLInfoInteger(MQL_LICENSE_TYPE);} 71 | static bool isFreeLicense() {return Mql::getLicenseType()==LICENSE_FREE;} 72 | static bool isDemoLicense() {return Mql::getLicenseType()==LICENSE_DEMO;} 73 | static bool isFullLicense() {return Mql::getLicenseType()==LICENSE_FULL;} 74 | static bool isTimeLicense() {return Mql::getLicenseType()==LICENSE_TIME;} 75 | 76 | static string getProgramName() {return MQLInfoString(MQL_PROGRAM_NAME);} 77 | static string getProgramPath() {return MQLInfoString(MQL_PROGRAM_PATH);} 78 | }; 79 | //+------------------------------------------------------------------+ 80 | //| Object getter/setter generator | 81 | //| ObjectAttr generates: | 82 | //| 1. private member m_property | 83 | //| 2. public method setProperty | 84 | //| 3. public method getProperty | 85 | //| ObjectAttrBool is specific to boolean type properties: | 86 | //| 1. private member m_isProperty | 87 | //| 2. public method setProperty | 88 | //| 3. public method isProperty | 89 | //| Use *Read or *Write versions for read only or write only | 90 | //| properties | 91 | //+------------------------------------------------------------------+ 92 | #define ObjectAttr(Type, Private, Public) \ 93 | public:\ 94 | Type get##Public() const {return m_##Private;}\ 95 | void set##Public(Type value) {m_##Private=value;}\ 96 | private:\ 97 | Type m_##Private\ 98 | 99 | #define ObjectAttrRead(Type, Private, Public) \ 100 | public:\ 101 | Type get##Public() const {return m_##Private;}\ 102 | private:\ 103 | Type m_##Private\ 104 | 105 | #define ObjectAttrWrite(Type, Private, Public) \ 106 | public:\ 107 | void set##Public(Type value) {m_##Private=value;}\ 108 | private:\ 109 | Type m_##Private\ 110 | 111 | #define ObjectAttrBool(Public) \ 112 | public:\ 113 | bool is##Public() const {return m_is##Public;}\ 114 | void set##Public(bool value) {m_is##Public=value;}\ 115 | private:\ 116 | bool m_is##Public\ 117 | 118 | #define ObjectAttrBoolRead(Public) \ 119 | public:\ 120 | bool is##Public() const {return m_is##Public;}\ 121 | private:\ 122 | bool m_is##Public\ 123 | 124 | #define ObjectAttrBoolWrite(Public) \ 125 | public:\ 126 | void set##Public(bool value) {m_is##Public=value;}\ 127 | private:\ 128 | bool m_##Private\ 129 | //+------------------------------------------------------------------+ 130 | //| Print debug messages: only generate code for debugging runs | 131 | //+------------------------------------------------------------------+ 132 | #ifdef _DEBUG 133 | #define Debug(msg) PrintFormat(">>> DEBUG[%s,%d,%s]: %s",__FILE__,__LINE__,__FUNCTION__,msg); 134 | #else 135 | #define Debug(msg) 136 | #endif 137 | //+------------------------------------------------------------------+ 138 | //| Execute some code in the global scope | 139 | //+------------------------------------------------------------------+ 140 | #define BEGIN_EXECUTE(Name) class __Execute##Name\ 141 | {\ 142 | public:__Execute##Name()\ 143 | { 144 | #define END_EXECUTE(Name) \ 145 | }\ 146 | }\ 147 | __execute##Name; 148 | //+------------------------------------------------------------------+ 149 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Include/Zmq/AtomicCounter.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Module: AtomicCounter.mqh | 3 | //| This file is part of the mql-zmq project: | 4 | //| https://github.com/dingmaotu/mql-zmq | 5 | //| | 6 | //| Copyright 2016-2017 Li Ding | 7 | //| | 8 | //| Licensed under the Apache License, Version 2.0 (the "License"); | 9 | //| you may not use this file except in compliance with the License. | 10 | //| You may obtain a copy of the License at | 11 | //| | 12 | //| http://www.apache.org/licenses/LICENSE-2.0 | 13 | //| | 14 | //| Unless required by applicable law or agreed to in writing, | 15 | //| software distributed under the License is distributed on an | 16 | //| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, | 17 | //| either express or implied. | 18 | //| See the License for the specific language governing permissions | 19 | //| and limitations under the License. | 20 | //+------------------------------------------------------------------+ 21 | #property strict 22 | 23 | #include 24 | 25 | #import "libzmq.dll" 26 | intptr_t zmq_atomic_counter_new(void); 27 | void zmq_atomic_counter_set(intptr_t counter,int value); 28 | int zmq_atomic_counter_inc(intptr_t counter); 29 | int zmq_atomic_counter_dec(intptr_t counter); 30 | int zmq_atomic_counter_value(intptr_t counter); 31 | void zmq_atomic_counter_destroy(intptr_t &counter_p); 32 | #import 33 | //+------------------------------------------------------------------+ 34 | //| Atomic counter utility | 35 | //+------------------------------------------------------------------+ 36 | class AtomicCounter 37 | { 38 | private: 39 | intptr_t m_ref; 40 | 41 | public: 42 | AtomicCounter() {m_ref=zmq_atomic_counter_new();} 43 | ~AtomicCounter() {zmq_atomic_counter_destroy(m_ref);} 44 | 45 | int increase() {return zmq_atomic_counter_inc(m_ref);} 46 | int decrease() {return zmq_atomic_counter_dec(m_ref);} 47 | int get() {return zmq_atomic_counter_value(m_ref);} 48 | void set(int value) {zmq_atomic_counter_set(m_ref,value);} 49 | }; 50 | //+------------------------------------------------------------------+ 51 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Include/Zmq/Context.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Module: Context.mqh | 3 | //| This file is part of the mql-zmq project: | 4 | //| https://github.com/dingmaotu/mql-zmq | 5 | //| | 6 | //| Copyright 2016-2017 Li Ding | 7 | //| | 8 | //| Licensed under the Apache License, Version 2.0 (the "License"); | 9 | //| you may not use this file except in compliance with the License. | 10 | //| You may obtain a copy of the License at | 11 | //| | 12 | //| http://www.apache.org/licenses/LICENSE-2.0 | 13 | //| | 14 | //| Unless required by applicable law or agreed to in writing, | 15 | //| software distributed under the License is distributed on an | 16 | //| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, | 17 | //| either express or implied. | 18 | //| See the License for the specific language governing permissions | 19 | //| and limitations under the License. | 20 | //+------------------------------------------------------------------+ 21 | #property strict 22 | #include 23 | #include 24 | #include 25 | #include "SocketOptions.mqh" 26 | 27 | //--- Context options 28 | #define ZMQ_IO_THREADS 1 29 | #define ZMQ_MAX_SOCKETS 2 30 | #define ZMQ_SOCKET_LIMIT 3 31 | #define ZMQ_THREAD_PRIORITY 3 32 | #define ZMQ_THREAD_SCHED_POLICY 4 33 | #define ZMQ_MAX_MSGSZ 5 34 | 35 | //--- Default for new contexts 36 | #define ZMQ_IO_THREADS_DFLT 1 37 | #define ZMQ_MAX_SOCKETS_DFLT 1023 38 | #define ZMQ_THREAD_PRIORITY_DFLT -1 39 | #define ZMQ_THREAD_SCHED_POLICY_DFLT -1 40 | 41 | #import "libzmq.dll" 42 | intptr_t zmq_ctx_new(void); 43 | int zmq_ctx_term(intptr_t context); 44 | int zmq_ctx_shutdown(intptr_t context); 45 | int zmq_ctx_set(intptr_t context,int option,int optval); 46 | int zmq_ctx_get(intptr_t context,int option); 47 | #import 48 | class ContextHandleManager: public HandleManager 49 | { 50 | intptr_t create() override 51 | { 52 | return zmq_ctx_new(); 53 | } 54 | void destroy(intptr_t handle) override 55 | { 56 | if(0!=zmq_ctx_term(handle)) 57 | { 58 | Debug("failed to terminate context"); 59 | } 60 | } 61 | }; 62 | //+------------------------------------------------------------------+ 63 | //| Wraps a 0MZ context | 64 | //| | 65 | //| Note on context creation: | 66 | //| In the official guide: | 67 | //| You should create and use exactly one context in your process. | 68 | //| Technically, the context is the container for all sockets in a | 69 | //| single process, and acts as the transport for inproc sockets, | 70 | //| which are the fastest way to connect threads in one process. | 71 | //| If at runtime a process has two contexts, these are like | 72 | //| separate ZeroMQ instances. | 73 | //| In metatrader Terminal, every Script and Expert Advsior has its | 74 | //| own thread, but they all share a process, that is the Terminal. | 75 | //| So it is advised to use a single global context on all your MQL | 76 | //| programs. The `shared` parameter is used for sychronization of | 77 | //| context creation and destruction. It is better named globally, | 78 | //| and in a manner not easily recognized by humans, for example: | 79 | //| "__3kewducdxhkd__" | 80 | //+------------------------------------------------------------------+ 81 | class Context: public GlobalHandle 82 | { 83 | protected: 84 | int get(int option) {return zmq_ctx_get(m_ref,option);} 85 | bool set(int option,int optval) {return 0==zmq_ctx_set(m_ref,option,optval);} 86 | 87 | public: 88 | 89 | static intptr_t create() {return zmq_ctx_new();} 90 | static void destroy(intptr_t handle) {if(0!=zmq_ctx_term(handle)) {Debug("failed to terminate context");}} 91 | 92 | Context(string shared=NULL):GlobalHandle(shared) {} 93 | 94 | bool shutdown() {return 0==zmq_ctx_shutdown(m_ref);} 95 | 96 | int getIoThreads() {return get(ZMQ_IO_THREADS);} 97 | void setIoThreads(int value) {if(!set(ZMQ_IO_THREADS,value)) {Debug("failed to set ZMQ_IO_THREADS");}} 98 | 99 | int getMaxSockets() {return get(ZMQ_MAX_SOCKETS);} 100 | void setMaxSockets(int value) {if(!set(ZMQ_MAX_SOCKETS,value)) {Debug("failed to set ZMQ_MAX_SOCKETS");}} 101 | 102 | int getMaxMessageSize() {return get(ZMQ_MAX_MSGSZ);} 103 | void setMaxMessageSize(int value) {if(!set(ZMQ_MAX_MSGSZ,value)) {Debug("failed to set ZMQ_MAX_MSGSZ");}} 104 | 105 | int getSocketLimit() {return get(ZMQ_SOCKET_LIMIT);} 106 | 107 | int getIpv6Options() {return get(ZMQ_IPV6);} 108 | void setIpv6Options(int value) {if(!set(ZMQ_IPV6,value)) {Debug("failed to set ZMQ_IPV6");}} 109 | 110 | bool isBlocky() {return 1==get(ZMQ_BLOCKY);} 111 | void setBlocky(bool value) {if(!set(ZMQ_BLOCKY,value?1:0)) {Debug("failed to set ZMQ_BLOCKY");}} 112 | 113 | //--- Following options is not supported on windows 114 | void setSchedulingPolicy(int value) {/*ZMQ_THREAD_SCHED_POLICY*/} 115 | void setThreadPriority(int value) {/*ZMQ_THREAD_PRIORITY*/} 116 | }; 117 | //+------------------------------------------------------------------+ 118 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Include/Zmq/Errno.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Module: Errno.mqh | 3 | //| This file is part of the mql-zmq project: | 4 | //| https://github.com/dingmaotu/mql-zmq | 5 | //| | 6 | //| Copyright 2016-2017 Li Ding | 7 | //| | 8 | //| Licensed under the Apache License, Version 2.0 (the "License"); | 9 | //| you may not use this file except in compliance with the License. | 10 | //| You may obtain a copy of the License at | 11 | //| | 12 | //| http://www.apache.org/licenses/LICENSE-2.0 | 13 | //| | 14 | //| Unless required by applicable law or agreed to in writing, | 15 | //| software distributed under the License is distributed on an | 16 | //| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, | 17 | //| either express or implied. | 18 | //| See the License for the specific language governing permissions | 19 | //| and limitations under the License. | 20 | //+------------------------------------------------------------------+ 21 | 22 | // Following error codes come from Microsoft CRT header errno.h 23 | 24 | // Error codes 25 | #define EPERM 1 26 | #define ENOENT 2 27 | #define ESRCH 3 28 | #define EINTR 4 29 | #define EIO 5 30 | #define ENXIO 6 31 | #define E2BIG 7 32 | #define ENOEXEC 8 33 | #define EBADF 9 34 | #define ECHILD 10 35 | #define EAGAIN 11 36 | #define ENOMEM 12 37 | #define EACCES 13 38 | #define EFAULT 14 39 | #define EBUSY 16 40 | #define EEXIST 17 41 | #define EXDEV 18 42 | #define ENODEV 19 43 | #define ENOTDIR 20 44 | #define EISDIR 21 45 | #define ENFILE 23 46 | #define EMFILE 24 47 | #define ENOTTY 25 48 | #define EFBIG 27 49 | #define ENOSPC 28 50 | #define ESPIPE 29 51 | #define EROFS 30 52 | #define EMLINK 31 53 | #define EPIPE 32 54 | #define EDOM 33 55 | #define EDEADLK 36 56 | #define ENAMETOOLONG 38 57 | #define ENOLCK 39 58 | #define ENOSYS 40 59 | #define ENOTEMPTY 41 60 | 61 | // Error codes used in the Secure CRT functions 62 | #define EINVAL 22 63 | #define ERANGE 34 64 | #define EILSEQ 42 65 | #define STRUNCATE 80 66 | 67 | // Support EDEADLOCK for compatibility with older Microsoft C versions 68 | #define EDEADLOCK EDEADLK 69 | 70 | // POSIX Supplement 71 | #define EALREADY 103 72 | #define EBADMSG 104 73 | #define ECANCELED 105 74 | #define EDESTADDRREQ 109 75 | #define EIDRM 111 76 | #define EISCONN 113 77 | #define ELOOP 114 78 | #define ENODATA 120 79 | #define ENOLINK 121 80 | #define ENOMSG 122 81 | #define ENOPROTOOPT 123 82 | #define ENOSR 124 83 | #define ENOSTR 125 84 | #define ENOTRECOVERABLE 127 85 | #define EOPNOTSUPP 130 86 | #define EOTHER 131 87 | #define EOVERFLOW 132 88 | #define EOWNERDEAD 133 89 | #define EPROTO 134 90 | #define EPROTOTYPE 136 91 | #define ETIME 137 92 | #define ETXTBSY 139 93 | #define EWOULDBLOCK 140 94 | 95 | // Following error codes come from zmq.h 96 | // 0MQ errors 97 | #define ZMQ_HAUSNUMERO 156384712 98 | 99 | #define ENOTSUP (ZMQ_HAUSNUMERO + 1) 100 | #define EPROTONOSUPPORT (ZMQ_HAUSNUMERO + 2) 101 | #define ENOBUFS (ZMQ_HAUSNUMERO + 3) 102 | #define ENETDOWN (ZMQ_HAUSNUMERO + 4) 103 | #define EADDRINUSE (ZMQ_HAUSNUMERO + 5) 104 | #define EADDRNOTAVAIL (ZMQ_HAUSNUMERO + 6) 105 | #define ECONNREFUSED (ZMQ_HAUSNUMERO + 7) 106 | #define EINPROGRESS (ZMQ_HAUSNUMERO + 8) 107 | #define ENOTSOCK (ZMQ_HAUSNUMERO + 9) 108 | #define EMSGSIZE (ZMQ_HAUSNUMERO + 10) 109 | #define EAFNOSUPPORT (ZMQ_HAUSNUMERO + 11) 110 | #define ENETUNREACH (ZMQ_HAUSNUMERO + 12) 111 | #define ECONNABORTED (ZMQ_HAUSNUMERO + 13) 112 | #define ECONNRESET (ZMQ_HAUSNUMERO + 14) 113 | #define ENOTCONN (ZMQ_HAUSNUMERO + 15) 114 | #define ETIMEDOUT (ZMQ_HAUSNUMERO + 16) 115 | #define EHOSTUNREACH (ZMQ_HAUSNUMERO + 17) 116 | #define ENETRESET (ZMQ_HAUSNUMERO + 18) 117 | 118 | // Native 0MQ error codes 119 | #define EFSM (ZMQ_HAUSNUMERO + 51) 120 | #define ENOCOMPATPROTO (ZMQ_HAUSNUMERO + 52) 121 | #define ETERM (ZMQ_HAUSNUMERO + 53) 122 | #define EMTHREAD (ZMQ_HAUSNUMERO + 54) 123 | //+------------------------------------------------------------------+ 124 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Include/Zmq/Z85.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Module: Z85.mqh | 3 | //| This file is part of the mql-zmq project: | 4 | //| https://github.com/dingmaotu/mql-zmq | 5 | //| | 6 | //| Copyright 2016-2017 Li Ding | 7 | //| | 8 | //| Licensed under the Apache License, Version 2.0 (the "License"); | 9 | //| you may not use this file except in compliance with the License. | 10 | //| You may obtain a copy of the License at | 11 | //| | 12 | //| http://www.apache.org/licenses/LICENSE-2.0 | 13 | //| | 14 | //| Unless required by applicable law or agreed to in writing, | 15 | //| software distributed under the License is distributed on an | 16 | //| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, | 17 | //| either express or implied. | 18 | //| See the License for the specific language governing permissions | 19 | //| and limitations under the License. | 20 | //+------------------------------------------------------------------+ 21 | #property strict 22 | 23 | #include 24 | 25 | #import "libzmq.dll" 26 | // Encode data with Z85 encoding. Returns 0(NULL) if failed 27 | intptr_t zmq_z85_encode(char &str[],const uchar &data[],size_t size); 28 | 29 | // Decode data with Z85 encoding. Returns 0(NULL) if failed 30 | intptr_t zmq_z85_decode(uchar &dest[],const char &str[]); 31 | 32 | // Generate z85-encoded public and private keypair with tweetnacl/libsodium 33 | int zmq_curve_keypair(char &z85_public_key[],char &z85_secret_key[]); 34 | 35 | // Derive the z85-encoded public key from the z85-encoded secret key 36 | int zmq_curve_public(char &z85_public_key[],const char &z85_secret_key[]); 37 | #import 38 | //+------------------------------------------------------------------+ 39 | //| Z85 encoding/decoding | 40 | //+------------------------------------------------------------------+ 41 | class Z85 42 | { 43 | public: 44 | static bool encode(string &secret,const uchar &data[]); 45 | static bool decode(const string secret,uchar &data[]); 46 | 47 | static string encode(string data); 48 | static string decode(string secret); 49 | 50 | static bool generateKeyPair(uchar &publicKey[],uchar &secretKey[]); 51 | static bool derivePublic(uchar &publicKey[],const uchar &secretKey[]); 52 | 53 | static bool generateKeyPair(string &publicKey,string &secretKey); 54 | static string derivePublic(const string secretKey); 55 | }; 56 | //+------------------------------------------------------------------+ 57 | //| data must have size multiple of 4 | 58 | //+------------------------------------------------------------------+ 59 | bool Z85::encode(string &secret,const uchar &data[]) 60 | { 61 | int size=ArraySize(data); 62 | if(size%4 != 0) return false; 63 | 64 | char str[]; 65 | ArrayResize(str,(int)(1.25*size+1)); 66 | 67 | intptr_t res=zmq_z85_encode(str,data,size); 68 | if(res == 0) return false; 69 | secret = StringFromUtf8(str); 70 | return true; 71 | } 72 | //+------------------------------------------------------------------+ 73 | //| secret must be multiples of 5 | 74 | //+------------------------------------------------------------------+ 75 | bool Z85::decode(const string secret,uchar &data[]) 76 | { 77 | int len=StringLen(secret); 78 | if(len%5 != 0) return false; 79 | 80 | char str[]; 81 | StringToUtf8(secret,str); 82 | ArrayResize(data,(int)(0.8*len)); 83 | return 0 != zmq_z85_decode(data,str); 84 | } 85 | //+------------------------------------------------------------------+ 86 | //| data length should be multiples of 4 and only ascii is supported | 87 | //+------------------------------------------------------------------+ 88 | string Z85::encode(string data) 89 | { 90 | char str[]; 91 | StringToUtf8(data,str,false); 92 | string res; 93 | if(encode(res,str)) 94 | return res; 95 | else 96 | return ""; 97 | } 98 | //+------------------------------------------------------------------+ 99 | //| secret must be multiples of 5 | 100 | //+------------------------------------------------------------------+ 101 | string Z85::decode(string secret) 102 | { 103 | uchar data[]; 104 | decode(secret,data); 105 | return StringFromUtf8(data); 106 | } 107 | //+------------------------------------------------------------------+ 108 | //| | 109 | //+------------------------------------------------------------------+ 110 | bool Z85::generateKeyPair(uchar &publicKey[],uchar &secretKey[]) 111 | { 112 | ArrayResize(publicKey,41); 113 | ArrayResize(secretKey,41); 114 | return 0==zmq_curve_keypair(publicKey, secretKey); 115 | } 116 | //+------------------------------------------------------------------+ 117 | //| | 118 | //+------------------------------------------------------------------+ 119 | bool Z85::derivePublic(uchar &publicKey[],const uchar &secretKey[]) 120 | { 121 | ArrayResize(publicKey,41); 122 | return 0==zmq_curve_public(publicKey, secretKey); 123 | } 124 | //+------------------------------------------------------------------+ 125 | //| | 126 | //+------------------------------------------------------------------+ 127 | bool Z85::generateKeyPair(string &publicKey,string &secretKey) 128 | { 129 | uchar sec[],pub[]; 130 | bool res=generateKeyPair(pub,sec); 131 | if(res) 132 | { 133 | secretKey=StringFromUtf8(sec); 134 | publicKey=StringFromUtf8(pub); 135 | } 136 | ArrayFree(sec); 137 | ArrayFree(pub); 138 | return res; 139 | } 140 | //+------------------------------------------------------------------+ 141 | //| | 142 | //+------------------------------------------------------------------+ 143 | string Z85::derivePublic(const string secrect) 144 | { 145 | uchar sec[],pub[]; 146 | StringToUtf8(secrect,sec); 147 | derivePublic(pub,sec); 148 | string pubstr=StringFromUtf8(pub); 149 | ArrayFree(sec); 150 | ArrayFree(pub); 151 | return pubstr; 152 | } 153 | //+------------------------------------------------------------------+ 154 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Include/Zmq/Zmq.mqh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Include/Zmq/Zmq.mqh -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Include/Zmq/ZmqMsg.mqh: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| Module: ZmqMsg.mqh | 3 | //| This file is part of the mql-zmq project: | 4 | //| https://github.com/dingmaotu/mql-zmq | 5 | //| | 6 | //| Copyright 2016-2017 Li Ding | 7 | //| | 8 | //| Licensed under the Apache License, Version 2.0 (the "License"); | 9 | //| you may not use this file except in compliance with the License. | 10 | //| You may obtain a copy of the License at | 11 | //| | 12 | //| http://www.apache.org/licenses/LICENSE-2.0 | 13 | //| | 14 | //| Unless required by applicable law or agreed to in writing, | 15 | //| software distributed under the License is distributed on an | 16 | //| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, | 17 | //| either express or implied. | 18 | //| See the License for the specific language governing permissions | 19 | //| and limitations under the License. | 20 | //+------------------------------------------------------------------+ 21 | #property strict 22 | #include 23 | #include 24 | //+------------------------------------------------------------------+ 25 | //| 0MQ Message struct | 26 | //+------------------------------------------------------------------+ 27 | // align sizeof(intptr_t) 28 | // = 8 on 64bit 29 | // = 4 on 32bit 30 | // hopefully MetaQuotes do malloc structs 31 | // aligned on pointer address boundaries 32 | struct zmq_msg_t 33 | { 34 | uchar _[64]; 35 | }; 36 | 37 | #import "libzmq.dll" 38 | int zmq_msg_init(zmq_msg_t &msg); 39 | int zmq_msg_init_size(zmq_msg_t &msg,size_t size); 40 | // As mt4 can not provide a zmq_free_fn, and can not let 41 | // zmq library own the array data, copying is always needed. 42 | // Therefore this function will not be used by this binding. 43 | // int zmq_msg_init_data(zmq_msg_t &msg,uchar &data[], 44 | // int size,int ffn,int hint); 45 | int zmq_msg_close(zmq_msg_t &msg); 46 | int zmq_msg_move(zmq_msg_t &dest,zmq_msg_t &src); 47 | int zmq_msg_copy(zmq_msg_t &dest,zmq_msg_t &src); 48 | // char * 49 | intptr_t zmq_msg_data(zmq_msg_t &msg); 50 | int zmq_msg_size(zmq_msg_t &msg); 51 | int zmq_msg_more(zmq_msg_t &msg); 52 | int zmq_msg_get(zmq_msg_t &msg,int property); 53 | int zmq_msg_set(zmq_msg_t &msg,int property,int optval); 54 | // const char * 55 | intptr_t zmq_msg_gets(zmq_msg_t &msg,const char &property[]); 56 | #import 57 | //+------------------------------------------------------------------+ 58 | //| Wraps a zmq_msg_t | 59 | //+------------------------------------------------------------------+ 60 | struct ZmqMsg: public zmq_msg_t 61 | { 62 | protected: 63 | int get(int property) {return zmq_msg_get(this,property);} 64 | bool set(int property,int value) {return 0==zmq_msg_set(this,property,value);} 65 | intptr_t data() {return zmq_msg_data(this);} 66 | bool setStringData(string data,bool nullterminated=false); 67 | public: 68 | ZmqMsg() {zmq_msg_init(this);} 69 | ZmqMsg(int size) {if(0!=zmq_msg_init_size(this,size)){Debug("Failed to init size msg: insufficient space");}} 70 | ZmqMsg(string data,bool nullterminated=false) {setStringData(data,nullterminated);} 71 | ~ZmqMsg() {if(0!=zmq_msg_close(this)){Debug("Failed to close msg");}} 72 | 73 | bool rebuild() 74 | { 75 | if(0!=zmq_msg_close(this)){Debug("Failed to close msg");return false;} 76 | return 0==zmq_msg_init(this); 77 | } 78 | bool rebuild(int size) 79 | { 80 | if(0!=zmq_msg_close(this)){Debug("Failed to close msg");return false;} 81 | return 0==zmq_msg_init_size(this,size); 82 | } 83 | bool rebuild(string data,bool nullterminated=false) 84 | { 85 | if(0!=zmq_msg_close(this)){Debug("Failed to close msg");return false;} 86 | return setStringData(data,nullterminated); 87 | } 88 | 89 | size_t size() {return zmq_msg_size(this);} 90 | 91 | void getData(uchar &bytes[]); 92 | string getData(); 93 | void setData(const uchar &bytes[]); 94 | 95 | bool more() {return 1==zmq_msg_more(this);} 96 | 97 | bool copy(ZmqMsg &msg) {return 0 == zmq_msg_copy(this, msg);} 98 | bool move(ZmqMsg &msg) {return 0 == zmq_msg_move(this, msg);} 99 | 100 | string meta(const string property); 101 | }; 102 | //+------------------------------------------------------------------+ 103 | //| Initialize a utf-8 string message | 104 | //+------------------------------------------------------------------+ 105 | bool ZmqMsg::setStringData(string data,bool nullterminated) 106 | { 107 | uchar array[]; 108 | StringToUtf8(data,array,nullterminated); 109 | bool res=(0==zmq_msg_init_size(this,ArraySize(array))); 110 | if(res)setData(array); 111 | return res; 112 | } 113 | //+------------------------------------------------------------------+ 114 | //| Get message data as bytes array | 115 | //+------------------------------------------------------------------+ 116 | void ZmqMsg::getData(uchar &bytes[]) 117 | { 118 | size_t size=size(); 119 | intptr_t src=data(); 120 | if(ArraySize(bytes) 12 | //+------------------------------------------------------------------+ 13 | //| Script program start function | 14 | //+------------------------------------------------------------------+ 15 | void OnStart() 16 | { 17 | //--- Test capabilities 18 | Print(">>> Testing capabilities"); 19 | Print("0) Zmq version is [",Zmq::getVersion(),"]"); 20 | Print("1) Supports ipc:// protocol: [",Zmq::hasIpc(),"]"); 21 | Print("2) Supports pgm:// protocol: [",Zmq::hasPgm(),"]"); 22 | Print("3) Supports norm:// protocol: [",Zmq::hasNorm(),"]"); 23 | Print("4) Supports tipc:// protocol: [",Zmq::hasTipc(),"]"); 24 | Print("5) Supports curve security: [",Zmq::hasCurve(),"]"); 25 | Print("6) Supports gssapi security: [",Zmq::hasGssApi(),"]"); 26 | Print(">>> End testing capabilities"); 27 | 28 | //--- Test Z85 encoding/decoding 29 | Print(">>> Testing Z85 encoding/decoding"); 30 | 31 | string data="12345678"; 32 | Print("1) Original data is: ",data); 33 | 34 | string secret=Z85::encode(data); 35 | Print("2) Encrypted value is: ",secret); 36 | 37 | string decoded=Z85::decode(secret); 38 | Print("3) Decoded: ",decoded); 39 | Print("4) Decoded value is equal to original: [",decoded==data,"]"); 40 | Print(">>> End testing Z85 encoding/decoding"); 41 | 42 | //--- Test atomic counters 43 | Print(">>> Testing atomic counters"); 44 | AtomicCounter counter; 45 | Print("1) Initial value should be 0: [",counter.get()==0,"]"); 46 | counter.set(5); 47 | Print("2) Counter set to 5: [",counter.get()==5,"]"); 48 | counter.increase(); 49 | Print("3) Increased value should be 6: [",counter.get()==6,"]"); 50 | counter.decrease(); 51 | Print("4) Decreased value should be 5: [",counter.get()==5,"]"); 52 | Print(">>> End testing atomic counters"); 53 | 54 | //--- Test context 55 | Print(">>> Testing context"); 56 | Context context; 57 | Print("1) Default IO threads should be ZMQ_IO_THREADS_DFLT: [",context.getIoThreads()==ZMQ_IO_THREADS_DFLT,"]"); 58 | Print(">>> trying to set io threads to 2"); 59 | context.setIoThreads(2); 60 | Print("2) Now IO threads should be 2: [",context.getIoThreads()==2,"]"); 61 | Print("3) Socket limit: [",context.getSocketLimit(),"]"); 62 | Print("4) Max sockets: [",context.getMaxSockets(),"]"); 63 | Print("5) Max message size: [",context.getMaxMessageSize(),"]"); 64 | Print(">>> End testing context"); 65 | 66 | Socket s(context,ZMQ_REP); 67 | string addr="inproc://abc"; 68 | if(!s.bind(addr)) 69 | { 70 | Debug(StringFormat("Error binding %s: %s",addr,Zmq::errorMessage())); 71 | } 72 | else 73 | { 74 | Debug(StringFormat("Success binded %s",addr)); 75 | } 76 | string endpoint; 77 | s.getLastEndpoint(endpoint); 78 | Print("Last endpoint is: [",endpoint,"]"); 79 | 80 | string principal; 81 | s.getGssApiPrincipal(principal); 82 | Print("Principal is [",principal,"]"); 83 | 84 | //--- Test curve 85 | Print(">>> Testing curve"); 86 | string genpub,gensec; 87 | Z85::generateKeyPair(genpub,gensec); 88 | Print("1) Generated public key: [",genpub,"]"); 89 | Print("1) Generated private key: [",gensec,"]"); 90 | Print("2) Derive public key from secret key: [",Z85::derivePublic(gensec)==genpub,"]"); 91 | Print(">>> End testing curve"); 92 | } 93 | //+------------------------------------------------------------------+ 94 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter1/HelloWorldClient.mq4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter1/HelloWorldClient.mq4 -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter1/HelloWorldServer.mq4: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| HelloWorldServer.mq5 | 3 | //| Copyright 2016, Li Ding | 4 | //| dingmaotu@hotmail.com | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2016, Li Ding" 7 | #property link "dingmaotu@hotmail.com" 8 | #property version "1.00" 9 | 10 | #include 11 | //+------------------------------------------------------------------+ 12 | //| Hello World server in MQL | 13 | //| Binds REP socket to tcp://*:5555 | 14 | //| Expects "Hello" from client, replies with "World" | 15 | //+------------------------------------------------------------------+ 16 | void OnStart() 17 | { 18 | Context context("helloworld"); 19 | Socket socket(context,ZMQ_REP); 20 | 21 | socket.bind("tcp://*:5555"); 22 | 23 | while(!IsStopped()) 24 | { 25 | ZmqMsg request; 26 | 27 | // Wait for next request from client 28 | 29 | // MetaTrader note: this will block the script thread 30 | // and if you try to terminate this script, MetaTrader 31 | // will hang (and crash if you force closing it) 32 | socket.recv(request); 33 | Print("Receive Hello"); 34 | 35 | Sleep(1000); 36 | 37 | ZmqMsg reply("World"); 38 | // Send reply back to client 39 | socket.send(reply); 40 | } 41 | } 42 | //+------------------------------------------------------------------+ 43 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter1/TaskEvent.mq4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter1/TaskEvent.mq4 -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter1/TaskSink.mq4: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| TaskSink.mq4 | 3 | //| Copyright 2017, Bear Two Technologies Co., Ltd. | 4 | //| dingmaotu@126.com | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Bear Two Technologies Co., Ltd." 7 | #property link "dingmaotu@126.com" 8 | #property version "1.00" 9 | #property strict 10 | 11 | #include 12 | //+------------------------------------------------------------------+ 13 | //| Task sink in MQL (adapted from C++ version) | 14 | //| Binds PULL socket to tcp://localhost:5558 | 15 | //| Collects results from workers via that socket | 16 | //| | 17 | //| Olivier Chamoux | 18 | //+------------------------------------------------------------------+ 19 | void OnStart() 20 | { 21 | //--- 22 | // Prepare our context and socket 23 | Context context; 24 | Socket receiver(context,ZMQ_PULL); 25 | receiver.bind("tcp://*:5558"); 26 | 27 | // Wait for start of batch 28 | ZmqMsg message; 29 | receiver.recv(message); 30 | 31 | // Start our clock now 32 | uint tstart=GetTickCount(); 33 | // Process 100 confirmations 34 | string progress=""; 35 | for(int i=0; i<100; i++) 36 | { 37 | receiver.recv(message); 38 | if((i/10)*10==i) 39 | progress+=":"; 40 | else 41 | progress+="."; 42 | Comment(progress); 43 | } 44 | // Calculate and report duration of batch 45 | uint tend=GetTickCount(); 46 | Print(">>> Total elapsed time: ",tend-tstart," msec"); 47 | } 48 | //+------------------------------------------------------------------+ 49 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter1/TaskWorker.mq4: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| TaskWorker.mq4 | 3 | //| Copyright 2017, Bear Two Technologies Co., Ltd. | 4 | //| dingmaotu@126.com | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Bear Two Technologies Co., Ltd." 7 | #property link "dingmaotu@126.com" 8 | #property version "1.00" 9 | #property strict 10 | #include 11 | //+------------------------------------------------------------------+ 12 | //| Task worker in MQL (adapted from C++ version) | 13 | //| Connects PULL socket to tcp://localhost:5557 | 14 | //| Collects workloads from ventilator via that socket | 15 | //| Connects PUSH socket to tcp://localhost:5558 | 16 | //| Sends results to sink via that socket | 17 | //| | 18 | //| Olivier Chamoux | 19 | //+------------------------------------------------------------------+ 20 | void OnStart() 21 | { 22 | //--- Share a single context in the terminal by the key "work" 23 | Context context("work"); 24 | 25 | //--- Socket to receive messages on 26 | Socket receiver(context,ZMQ_PULL); 27 | receiver.connect("tcp://localhost:5557"); 28 | 29 | //--- Socket to send messages to 30 | Socket sender(context,ZMQ_PUSH); 31 | sender.connect("tcp://localhost:5558"); 32 | 33 | //--- Process tasks forever 34 | string progress=""; 35 | while(!IsStopped()) 36 | { 37 | ZmqMsg message; 38 | receiver.recv(message); 39 | //--- Workload in msecs 40 | int workload=(int)StringToInteger(message.getData()); 41 | //--- Do the work 42 | Sleep(workload); 43 | //--- Send results to sink 44 | message.rebuild(); 45 | sender.send(message); 46 | 47 | // Simple progress indicator for the viewer 48 | progress+="."; 49 | Comment(progress); 50 | } 51 | } 52 | //+------------------------------------------------------------------+ 53 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter1/VersionReporting.mq4: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| VersionReporting.mq4.mq4 | 3 | //| Copyright 2016, Li Ding | 4 | //| dingmaotu@hotmail.com | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2016, Li Ding" 7 | #property link "dingmaotu@hotmail.com" 8 | #property version "1.00" 9 | #property strict 10 | 11 | #include 12 | //+------------------------------------------------------------------+ 13 | //| Report 0MQ version | 14 | //+------------------------------------------------------------------+ 15 | void OnStart() 16 | { 17 | Print(Zmq::getVersion()); 18 | } 19 | //+------------------------------------------------------------------+ 20 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter1/WeatherUpdateClient.mq4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter1/WeatherUpdateClient.mq4 -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter1/WeatherUpdateServer.mq4: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| WeatherUpdateServer.mq4.mq4 | 3 | //| Copyright 2016, Li Ding | 4 | //| dingmaotu@hotmail.com | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2016, Li Ding" 7 | #property link "dingmaotu@hotmail.com" 8 | #property version "1.00" 9 | #property strict 10 | 11 | #include 12 | 13 | #define within(num) (int) ((float) num * MathRand() / (32767 + 1.0)) 14 | //+------------------------------------------------------------------+ 15 | //| Weather update server in MQL | 16 | //| Binds PUB socket to tcp://*:5556 | 17 | //| Publishes random weather updates | 18 | //+------------------------------------------------------------------+ 19 | void OnStart() 20 | { 21 | //--- Prepare our context and publisher 22 | Context context; 23 | Socket publisher(context,ZMQ_PUB); 24 | publisher.bind("tcp://*:5556"); 25 | 26 | long messages_sent=0; 27 | //--- Initialize random number generator 28 | MathSrand(GetTickCount()); 29 | while(!IsStopped()) 30 | { 31 | int zipcode,temperature,relhumidity; 32 | 33 | // Get values that will fool the boss 34 | 35 | // MetaTrader Note: 36 | // if RAND_MAX < 100000, which is the case for MetaTrader, 37 | // you may never get the required value 38 | // So 30000 might be a good alternative 39 | zipcode=within(30000); 40 | temperature=within(215) - 80; 41 | relhumidity=within(50) + 10; 42 | 43 | // Send message to all subscribers 44 | ZmqMsg message(StringFormat("%05d %d %d",zipcode,temperature,relhumidity)); 45 | publisher.send(message); 46 | messages_sent++; 47 | 48 | if(messages_sent%1000000==0) 49 | { 50 | PrintFormat("Sent %dM messages now.",messages_sent/1000000); 51 | } 52 | } 53 | } 54 | //+------------------------------------------------------------------+ 55 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter2/MSPoller.mq4: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| MSPoller.mq4 | 3 | //| Copyright 2017, Li Ding | 4 | //| dingmaotu@126.com | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Li Ding" 7 | #property link "dingmaotu@126.com" 8 | #property version "1.00" 9 | #property strict 10 | #include 11 | //+------------------------------------------------------------------+ 12 | //| Reading from multiple sockets in MQL (adapted from C++ version) | 13 | //| This version uses zmq_poll() | 14 | //| | 15 | //| Olivier Chamoux | 16 | //+------------------------------------------------------------------+ 17 | void OnStart() 18 | { 19 | //--- 20 | Context context; 21 | 22 | // Connect to task ventilator 23 | Socket receiver(context,ZMQ_PULL); 24 | receiver.connect("tcp://localhost:5557"); 25 | 26 | // Connect to weather server 27 | Socket subscriber(context,ZMQ_SUB); 28 | subscriber.connect("tcp://localhost:5556"); 29 | subscriber.subscribe("10001 "); 30 | 31 | // Initialize poll set 32 | PollItem items[2]; 33 | receiver.fillPollItem(items[0],ZMQ_POLLIN); 34 | subscriber.fillPollItem(items[1],ZMQ_POLLIN); 35 | // Process messages from both sockets 36 | while(!IsStopped()) 37 | { 38 | ZmqMsg message; 39 | //--- MQL Note: To handle Script exit properly, we set a timeout of 500 ms instead of infinite wait 40 | Socket::poll(items,500); 41 | 42 | if(items[0].hasInput()) 43 | { 44 | receiver.recv(message); 45 | // Process task 46 | } 47 | if(items[1].hasInput()) 48 | { 49 | subscriber.recv(message); 50 | // Process weather update 51 | } 52 | } 53 | } 54 | //+------------------------------------------------------------------+ 55 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter2/RRBroker.mq4: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| RRBroker.mq4 | 3 | //| Copyright 2017, Li Ding | 4 | //| dingmaotu@126.com | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Li Ding" 7 | #property link "dingmaotu@126.com" 8 | #property version "1.00" 9 | #property strict 10 | #include 11 | //+------------------------------------------------------------------+ 12 | //| Simple request-reply broker in MQL (adapted from C++ version) | 13 | //| | 14 | //| Olivier Chamoux | 15 | //+------------------------------------------------------------------+ 16 | void OnStart() 17 | { 18 | // Prepare our context and sockets 19 | Context context; 20 | Socket frontend(context,ZMQ_ROUTER); 21 | Socket backend(context,ZMQ_DEALER); 22 | 23 | frontend.bind("tcp://*:5559"); 24 | backend.bind("tcp://*:5560"); 25 | 26 | // Initialize poll set 27 | PollItem items[2]; 28 | frontend.fillPollItem(items[0],ZMQ_POLLIN); 29 | backend.fillPollItem(items[1],ZMQ_POLLIN); 30 | 31 | // Switch messages between sockets 32 | while(!IsStopped()) 33 | { 34 | ZmqMsg message; 35 | bool more=false; // Multipart detection 36 | 37 | Socket::poll(items,500); 38 | 39 | if(items[0].hasInput()) 40 | { 41 | // Process all parts of the message 42 | do 43 | { 44 | frontend.recv(message); 45 | if(message.more()) backend.sendMore(message); 46 | else backend.send(message); 47 | } 48 | while(more); 49 | } 50 | if(items[1].hasInput()) 51 | { 52 | // Process all parts of the message 53 | do 54 | { 55 | backend.recv(message); 56 | if(message.more()) frontend.sendMore(message); 57 | else frontend.send(message); 58 | } 59 | while(more); 60 | } 61 | } 62 | } 63 | //+------------------------------------------------------------------+ 64 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter2/RRClient.mq4: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| RRClient.mq4 | 3 | //| Copyright 2017, Li Ding | 4 | //| dingmaotu@126.com | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Li Ding" 7 | #property link "dingmaotu@126.com" 8 | #property version "1.00" 9 | #property strict 10 | #include 11 | //+------------------------------------------------------------------+ 12 | //| Request-reply client in MQL (adapted from C++ version) | 13 | //| Connects REQ socket to tcp://localhost:5559 | 14 | //| Sends "Hello" to server, expects "World" back | 15 | //| | 16 | //| Olivier Chamoux | 17 | //+------------------------------------------------------------------+ 18 | void OnStart() 19 | { 20 | Context context; 21 | 22 | Socket requester(context,ZMQ_REQ); 23 | requester.connect("tcp://localhost:5559"); 24 | 25 | for(int request=0; request<10; request++) 26 | { 27 | ZmqMsg message("Hello"); 28 | requester.send(message); 29 | 30 | ZmqMsg reply; 31 | requester.recv(reply,true); 32 | 33 | Print("Received reply ",reply.getData()); 34 | } 35 | } 36 | //+------------------------------------------------------------------+ 37 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter2/RRWorker.mq4: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| RRWorker.mq4 | 3 | //| Copyright 2017, Li Ding | 4 | //| dingmaotu@126.com | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Li Ding" 7 | #property link "dingmaotu@126.com" 8 | #property version "1.00" 9 | #property strict 10 | #include 11 | //+------------------------------------------------------------------+ 12 | //| Request-reply service in MQL (adapted from C++ version) | 13 | //| Connects REP socket to tcp://localhost:5560 | 14 | //| Expects "Hello" from client, replies with "World" | 15 | //| | 16 | //| Olivier Chamoux | 17 | //+------------------------------------------------------------------+ 18 | void OnStart() 19 | { 20 | Context context; 21 | 22 | Socket responder(context,ZMQ_REP); 23 | responder.connect("tcp://localhost:5560"); 24 | 25 | while(!IsStopped()) 26 | { 27 | // Wait for next request from client 28 | ZmqMsg req; 29 | responder.recv(req); 30 | Print("Received request: ",req.getData()); 31 | 32 | // Do some 'work' 33 | Sleep(1000); 34 | 35 | ZmqMsg reply("World"); 36 | 37 | // Send reply back to client 38 | responder.send(reply); 39 | } 40 | } 41 | //+------------------------------------------------------------------+ 42 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter2/WUProxy.mq4: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| WUProxy.mq4 | 3 | //| Copyright 2017, Li Ding | 4 | //| dingmaotu@126.com | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Li Ding" 7 | #property link "dingmaotu@126.com" 8 | #property version "1.00" 9 | #property strict 10 | #include 11 | //+------------------------------------------------------------------+ 12 | //| Weather proxy device MQL (adapted from C++) | 13 | //| | 14 | //| Olivier Chamoux | 15 | //+------------------------------------------------------------------+ 16 | void OnStart() 17 | { 18 | //--- 19 | Context context; 20 | 21 | // This is where the weather server sits 22 | Socket frontend(context,ZMQ_XSUB); 23 | frontend.connect("tcp://192.168.55.210:5556"); 24 | 25 | // This is our public endpoint for subscribers 26 | Socket backend(context,ZMQ_XPUB); 27 | backend.bind("tcp://10.1.1.0:8100"); 28 | 29 | // Subscribe on everything 30 | frontend.subscribe(""); 31 | 32 | // Shunt messages out to our own subscribers 33 | while(!IsStopped()) 34 | { 35 | // Process all parts of the message 36 | ZmqMsg message; 37 | bool more; 38 | do 39 | { 40 | frontend.recv(message); 41 | if(message.more()) backend.sendMore(message); 42 | else backend.send(message); 43 | } 44 | while(more); 45 | } 46 | } 47 | //+------------------------------------------------------------------+ 48 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/dependencies/mql-zmq-master/mql-zmq-master/Scripts/ZeroMQGuideExamples/Chapter3/RTReqBroker.mq4: -------------------------------------------------------------------------------- 1 | //+------------------------------------------------------------------+ 2 | //| RTReqBroker.mq4 | 3 | //| Copyright 2017, Li Ding | 4 | //| dingmaotu@126.com | 5 | //+------------------------------------------------------------------+ 6 | #property copyright "Copyright 2017, Li Ding" 7 | #property link "dingmaotu@126.com" 8 | #property version "1.00" 9 | #property strict 10 | #property show_inputs 11 | //+------------------------------------------------------------------+ 12 | //| This example comes from the "Load Balancing Pattern" | 13 | //| The original example creates threads for workers and spawn them | 14 | //| in the broker main thread. MetaTrader Terminal does not support | 15 | //| thread creation. So we split the broker and worker code to two | 16 | //| scripts. Since we splitted the code, we need to wait all workers | 17 | //| connect. | 18 | //| This is the broker part. | 19 | //+------------------------------------------------------------------+ 20 | #include 21 | input int InpNumberWorkers=5; 22 | //+------------------------------------------------------------------+ 23 | //| Custom routing Router to Mama (ROUTER to REQ) (adapted from C++) | 24 | //| Olivier Chamoux | 25 | //+------------------------------------------------------------------+ 26 | void OnStart() 27 | { 28 | Context context("rtreq"); 29 | Socket broker(context,ZMQ_ROUTER); 30 | broker.bind("inproc://rtreq"); 31 | 32 | string identities[]; 33 | ArrayResize(identities,InpNumberWorkers); 34 | // Wait until InpNumberWorkers workers connected 35 | for(int i=0; i 11 | #property show_inputs 12 | //+------------------------------------------------------------------+ 13 | //| This example comes from the "Load Balancing Pattern" | 14 | //| The original example creates threads for workers and spawn them | 15 | //| in the broker main thread. MetaTrader Terminal does not support | 16 | //| thread creation. So we split the broker and worker code to two | 17 | //| scripts. Since we splitted the code, we need to wait all workers | 18 | //| connect. | 19 | //| This is the worker part. | 20 | //| For the worker, we can use either ZMQ_REQ or ZMQ_DEALER, the | 21 | //| difference is minimal. When using a dealer socket, remember to | 22 | //| send an empty frame to emulate the REQ behavior. | 23 | //+------------------------------------------------------------------+ 24 | 25 | #define within(num) (int) ((float) num * MathRand() / (32767 + 1.0)) 26 | 27 | input string InpWorkerIdentity="worker1"; 28 | //+------------------------------------------------------------------+ 29 | //| Custom routing Router to Mama (ROUTER to REQ) (adapted from C++) | 30 | //| The worker | 31 | //| Olivier Chamoux | 32 | //+------------------------------------------------------------------+ 33 | void OnStart() 34 | { 35 | //--- use inproc 36 | Context context("rtreq"); 37 | Socket worker(context,ZMQ_REQ); 38 | //--- We use a string identity for ease here 39 | worker.setIdentity(InpWorkerIdentity); 40 | worker.connect("inproc://rtreq"); 41 | 42 | ZmqMsg msg("Connect!"); 43 | worker.send(msg); 44 | worker.recv(msg); 45 | Print(InpWorkerIdentity," connect: ",msg.getData()); 46 | 47 | int total=0; 48 | while(!IsStopped()) 49 | { 50 | // Tell the broker we're ready for work 51 | worker.send("Hi Boss"); 52 | 53 | // Get workload from broker, until finished 54 | worker.recv(msg); 55 | string workload=msg.getData(); 56 | if("Fired!"==workload) 57 | { 58 | Print(InpWorkerIdentity," is fired!"); 59 | Print(InpWorkerIdentity," processed: ",total," tasks"); 60 | break; 61 | } 62 | else 63 | { 64 | Print(InpWorkerIdentity," received work!"); 65 | } 66 | total++; 67 | 68 | // Do some random work 69 | Sleep(within(500)+1); 70 | } 71 | } 72 | //+------------------------------------------------------------------+ 73 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/resources/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/resources/images/1200x628-twitter-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/resources/images/1200x628-twitter-4.jpg -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/resources/images/InAction_ZeroMQ_Server_Publishing_Symbol_Data.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/resources/images/InAction_ZeroMQ_Server_Publishing_Symbol_Data.gif -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/resources/images/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/resources/images/ZeroMQ_Server_Publishing_Symbol_Data.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/resources/images/ZeroMQ_Server_Publishing_Symbol_Data.gif -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/resources/images/dwx-zeromq-infographic-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/resources/images/dwx-zeromq-infographic-1.png -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/resources/images/expert-inputs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/resources/images/expert-inputs.png -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/resources/images/expert-inputs_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/dwx-zeromq-connector-master/resources/images/expert-inputs_old.png -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/mql4/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/python/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/python/api/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/python/api/requirements.txt: -------------------------------------------------------------------------------- 1 | zmq 2 | pandas 3 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/python/examples/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/python/examples/template/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/python/examples/template/modules/DWX_ZMQ_Execution.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | DWX_ZMQ_Execution.py 4 | -- 5 | @author: Darwinex Labs (www.darwinex.com) 6 | 7 | Copyright (c) 2019 onwards, Darwinex. All rights reserved. 8 | 9 | Licensed under the BSD 3-Clause License, you may not use this file except 10 | in compliance with the License. 11 | 12 | You may obtain a copy of the License at: 13 | https://opensource.org/licenses/BSD-3-Clause 14 | """ 15 | 16 | from pandas import to_datetime 17 | from time import sleep 18 | 19 | class DWX_ZMQ_Execution(): 20 | 21 | def __init__(self, _zmq): 22 | self._zmq = _zmq 23 | 24 | ########################################################################## 25 | 26 | def _execute_(self, 27 | _exec_dict, 28 | _verbose=False, 29 | _delay=0.1, 30 | _wbreak=10): 31 | 32 | _check = '' 33 | 34 | # Reset thread data output 35 | self._zmq._set_response_(None) 36 | 37 | # OPEN TRADE 38 | if _exec_dict['_action'] == 'OPEN': 39 | 40 | _check = '_action' 41 | self._zmq._DWX_MTX_NEW_TRADE_(_order=_exec_dict) 42 | 43 | # CLOSE TRADE 44 | elif _exec_dict['_action'] == 'CLOSE': 45 | 46 | _check = '_response_value' 47 | self._zmq._DWX_MTX_CLOSE_TRADE_BY_TICKET_(_exec_dict['_ticket']) 48 | 49 | if _verbose: 50 | print('\n[{}] {} -> MetaTrader'.format(_exec_dict['_comment'], 51 | str(_exec_dict))) 52 | 53 | # While loop start time reference 54 | _ws = to_datetime('now') 55 | 56 | # While data not received, sleep until timeout 57 | while self._zmq._valid_response_('zmq') == False: 58 | sleep(_delay) 59 | 60 | if (to_datetime('now') - _ws).total_seconds() > (_delay * _wbreak): 61 | break 62 | 63 | # If data received, return DataFrame 64 | if self._zmq._valid_response_('zmq'): 65 | 66 | if _check in self._zmq._get_response_().keys(): 67 | return self._zmq._get_response_() 68 | 69 | # Default 70 | return None 71 | 72 | ########################################################################## 73 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/python/examples/template/modules/DWX_ZMQ_Reporting.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | DWX_ZMQ_Reporting.py 4 | -- 5 | @author: Darwinex Labs (www.darwinex.com) 6 | 7 | Copyright (c) 2019 onwards, Darwinex. All rights reserved. 8 | 9 | Licensed under the BSD 3-Clause License, you may not use this file except 10 | in compliance with the License. 11 | 12 | You may obtain a copy of the License at: 13 | https://opensource.org/licenses/BSD-3-Clause 14 | """ 15 | 16 | from pandas import DataFrame, to_datetime 17 | from time import sleep 18 | 19 | class DWX_ZMQ_Reporting(): 20 | 21 | def __init__(self, _zmq): 22 | self._zmq = _zmq 23 | 24 | ########################################################################## 25 | 26 | def _get_open_trades_(self, _trader='Trader_SYMBOL', 27 | _delay=0.1, _wbreak=10): 28 | 29 | # Reset data output 30 | self._zmq._set_response_(None) 31 | 32 | # Get open trades from MetaTrader 33 | self._zmq._DWX_MTX_GET_ALL_OPEN_TRADES_() 34 | 35 | # While loop start time reference 36 | _ws = to_datetime('now') 37 | 38 | # While data not received, sleep until timeout 39 | while self._zmq._valid_response_('zmq') == False: 40 | 41 | sleep(_delay) 42 | 43 | if (to_datetime('now') - _ws).total_seconds() > (_delay * _wbreak): 44 | break 45 | 46 | # If data received, return DataFrame 47 | if self._zmq._valid_response_('zmq'): 48 | 49 | _response = self._zmq._get_response_() 50 | 51 | if ('_trades' in _response.keys() 52 | and len(_response['_trades']) > 0): 53 | 54 | _df = DataFrame(data=_response['_trades'].values(), 55 | index=_response['_trades'].keys()) 56 | return _df[_df['_comment'] == _trader] 57 | 58 | # Default 59 | return DataFrame() 60 | 61 | ########################################################################## 62 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/python/examples/template/modules/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/python/examples/template/strategies/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/python/examples/template/strategies/base/DWX_ZMQ_Strategy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | DWX_ZMQ_Strategy.py 4 | -- 5 | @author: Darwinex Labs (www.darwinex.com) 6 | 7 | Copyright (c) 2019 onwards, Darwinex. All rights reserved. 8 | 9 | Licensed under the BSD 3-Clause License, you may not use this file except 10 | in compliance with the License. 11 | 12 | You may obtain a copy of the License at: 13 | https://opensource.org/licenses/BSD-3-Clause 14 | """ 15 | 16 | from api.DWX_ZeroMQ_Connector_v2_0_1_RC8 import DWX_ZeroMQ_Connector 17 | from examples.template.modules.DWX_ZMQ_Execution import DWX_ZMQ_Execution 18 | from examples.template.modules.DWX_ZMQ_Reporting import DWX_ZMQ_Reporting 19 | 20 | class DWX_ZMQ_Strategy(object): 21 | 22 | def __init__(self, _name="DEFAULT_STRATEGY", # Name 23 | _symbols=[('EURUSD',0.01), # List of (Symbol,Lotsize) tuples 24 | ('AUDNZD',0.01), 25 | ('NDX',0.10), 26 | ('UK100',0.1), 27 | ('GDAXI',0.01), 28 | ('XTIUSD',0.01), 29 | ('SPX500',1.0), 30 | ('STOXX50E',0.10), 31 | ('XAUUSD',0.01)], 32 | _broker_gmt=3, # Darwinex GMT offset 33 | _pulldata_handlers = [], # Handlers to process data received through PULL port. 34 | _subdata_handlers = [], # Handlers to process data received through SUB port. 35 | _verbose=False): # Print ZeroMQ messages 36 | 37 | self._name = _name 38 | self._symbols = _symbols 39 | self._broker_gmt = _broker_gmt 40 | 41 | # Not entirely necessary here. 42 | self._zmq = DWX_ZeroMQ_Connector(_pulldata_handlers=_pulldata_handlers, 43 | _subdata_handlers=_subdata_handlers, 44 | _verbose=_verbose) 45 | 46 | # Modules 47 | self._execution = DWX_ZMQ_Execution(self._zmq) 48 | self._reporting = DWX_ZMQ_Reporting(self._zmq) 49 | 50 | ########################################################################## 51 | 52 | def _run_(self): 53 | 54 | """ 55 | Enter strategy logic here 56 | """ 57 | 58 | ########################################################################## 59 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/python/examples/template/strategies/base/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dwx-zeromq-connector-master/v2.0.1/python/examples/template/strategies/rates_historic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | rates_historic.py 6 | 7 | An example using the Darwinex ZeroMQ Connector for Python 3 and MetaTrader 4 PULL REQUEST 8 | for v2.0.1 in which a Client requests rate history from EURGBP Daily from 2019.01.04 to 9 | to 2019.01.14. 10 | 11 | 12 | ------------------- 13 | Rates history: 14 | ------------------- 15 | Through commmand HIST, this client can select multiple rates from an INSTRUMENT (symbol, timeframe). 16 | For example, to receive rates from instruments EURUSD(M1), between two dates, it will send this 17 | command to the Server, through its PUSH channel: 18 | 19 | "HIST;EURUSD;1;2019.01.04 00:00:00;2019.01.14 00:00:00" 20 | 21 | -- 22 | 23 | @author: [raulMrello](https://www.linkedin.com/in/raul-martin-19254530/) 24 | 25 | """ 26 | 27 | 28 | ############################################################################# 29 | # DWX-ZMQ required imports 30 | ############################################################################# 31 | 32 | 33 | # Append path for main project folder 34 | import sys 35 | sys.path.append('../../..') 36 | 37 | # Import ZMQ-Strategy from relative path 38 | from examples.template.strategies.base.DWX_ZMQ_Strategy import DWX_ZMQ_Strategy 39 | 40 | 41 | ############################################################################# 42 | # Other required imports 43 | ############################################################################# 44 | 45 | import os 46 | from pandas import Timedelta, to_datetime, Timestamp 47 | from threading import Thread, Lock 48 | from time import sleep 49 | import random 50 | 51 | 52 | ############################################################################# 53 | # Class derived from DWZ_ZMQ_Strategy includes data processor for PULL,SUB data 54 | ############################################################################# 55 | 56 | class rates_historic(DWX_ZMQ_Strategy): 57 | 58 | def __init__(self, 59 | _name="PRICES_SUBSCRIPTIONS", 60 | _delay=0.1, 61 | _broker_gmt=3, 62 | _verbose=False): 63 | 64 | # call DWX_ZMQ_Strategy constructor and passes itself as data processor for handling 65 | # received data on PULL and SUB ports 66 | super().__init__(_name, 67 | [], # Empty symbol list (not needed for this example) 68 | _broker_gmt, 69 | [self], # Registers itself as handler of pull data via self.onPullData() 70 | [self], # Registers itself as handler of sub data via self.onSubData() 71 | _verbose) 72 | 73 | # This strategy's variables 74 | self._delay = _delay 75 | self._verbose = _verbose 76 | self._finished = False 77 | 78 | # lock for acquire/release of ZeroMQ connector 79 | self._lock = Lock() 80 | 81 | ########################################################################## 82 | def isFinished(self): 83 | """ Check if execution finished""" 84 | return self._finished 85 | 86 | ########################################################################## 87 | def onPullData(self, data): 88 | """ 89 | Callback to process new data received through the PULL port 90 | """ 91 | # print responses to request commands 92 | print('Historic from ExpertAdvisor={}'.format(data)) 93 | 94 | 95 | ########################################################################## 96 | def onSubData(self, data): 97 | """ 98 | Callback to process new data received through the SUB port 99 | """ 100 | # split msg to get topic and message 101 | _topic, _msg = data.split(" ") 102 | print('Data on Topic={} with Message={}'.format(_topic, _msg)) 103 | 104 | 105 | 106 | ########################################################################## 107 | def run(self): 108 | """ 109 | Request historic data 110 | """ 111 | self._finished = False 112 | 113 | # request rates 114 | print('Requesting Daily Rates from EURGBP') 115 | self._zmq._DWX_MTX_SEND_HIST_REQUEST_(_symbol='EURGBP', 116 | _timeframe=1440, 117 | _start='2020.05.04 00:00:00', 118 | _end ='2020.05.14 00:00:00') 119 | sleep(1) 120 | print('\nHistory Data Dictionary:') 121 | print(self._zmq._History_DB) 122 | 123 | # finishes (removes all subscriptions) 124 | self.stop() 125 | 126 | ########################################################################## 127 | def stop(self): 128 | """ 129 | unsubscribe from all market symbols and exits 130 | """ 131 | 132 | # remove subscriptions and stop symbols price feeding 133 | try: 134 | # Acquire lock 135 | self._lock.acquire() 136 | self._zmq._DWX_MTX_UNSUBSCRIBE_ALL_MARKETDATA_REQUESTS_() 137 | print('Unsubscribing from all topics') 138 | 139 | finally: 140 | # Release lock 141 | self._lock.release() 142 | sleep(self._delay) 143 | 144 | self._finished = True 145 | 146 | 147 | 148 | """ ----------------------------------------------------------------------------------------------- 149 | ----------------------------------------------------------------------------------------------- 150 | SCRIPT SETUP 151 | ----------------------------------------------------------------------------------------------- 152 | ----------------------------------------------------------------------------------------------- 153 | """ 154 | if __name__ == "__main__": 155 | 156 | # creates object with a predefined configuration: historic EURGBP_D1 between 4th adn 14th January 2019 157 | print('Loading example...') 158 | example = rates_historic() 159 | 160 | # Starts example execution 161 | print('unning example...') 162 | example.run() 163 | 164 | # Waits example termination 165 | print('Waiting example termination...') 166 | while not example.isFinished(): 167 | sleep(1) 168 | print('Bye!!!') 169 | -------------------------------------------------------------------------------- /factor_framework/pipeline.py: -------------------------------------------------------------------------------- 1 | from scipy.stats import rankdata 2 | 3 | class Factor(): 4 | 5 | def __init__(self, formula, data): 6 | self.formula = formula 7 | self.data = data 8 | self.weights = None 9 | 10 | def calculate_weight(self): 11 | pass 12 | 13 | def neutralize(self): 14 | pass 15 | 16 | def rank(self, vector): 17 | """Take in a vector values, return ranks in [0, 1]""" 18 | ranks = rankdata(vector) 19 | normalized_ranks = (ranks - 1) / (len(vector) - 1) 20 | 21 | return normalized_ranks 22 | 23 | 24 | class Backtest(): 25 | 26 | def __init__(self, historical_data, weights, start_dt, end_dt) -> None: 27 | self.historical_data = historical_data 28 | self.weights = weights 29 | self.start_dt = start_dt 30 | self.end_dt = end_dt 31 | 32 | def calculate_metrics(self): 33 | pass 34 | 35 | def plot(self): 36 | pass 37 | 38 | -------------------------------------------------------------------------------- /factor_framework/run.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | def run(weight_formula): 4 | pass -------------------------------------------------------------------------------- /playground/long_symbols.csv: -------------------------------------------------------------------------------- 1 | ,0 2 | 0,['TOMOUSDT'] 3 | 1,[] 4 | 2,['KSMUSDT'] 5 | 3,[] 6 | 4,[] 7 | 5,['KLAYUSDT'] 8 | 6,['XMRUSDT'] 9 | 7,[] 10 | 8,[] 11 | 9,[] 12 | 10,['DUSKUSDT'] 13 | 11,['ONEUSDT'] 14 | 12,[] 15 | 13,['DOGEUSDT'] 16 | 14,[] 17 | 15,"['TRXUSDT', 'XEMUSDT', 'BTCDOMUSDT']" 18 | 16,"['BTCUSDT', 'XRPUSDT', 'TRXUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 19 | 17,"['XRPUSDT', 'TRXUSDT', 'CTKUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 20 | 18,"['XRPUSDT', 'TRXUSDT', 'EGLDUSDT', 'XEMUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 21 | 19,['XMRUSDT'] 22 | 20,['NEARUSDT'] 23 | 21,"['ADAUSDT', 'XMRUSDT', 'ALGOUSDT', 'BNXUSDT']" 24 | 22,"['ADAUSDT', 'NEARUSDT']" 25 | 23,"['ADAUSDT', 'NEARUSDT', 'COTIUSDT']" 26 | 24,['ADAUSDT'] 27 | 25,['CTSIUSDT'] 28 | 26,"['XRPUSDT', 'BTCDOMUSDT']" 29 | 27,"['TRXUSDT', 'BTCDOMUSDT']" 30 | 28,"['TRXUSDT', 'XMRUSDT', 'DODOBUSD']" 31 | 29,['BTCDOMUSDT'] 32 | 30,"['MKRUSDT', 'BTCDOMUSDT']" 33 | 31,[] 34 | 32,['SFPUSDT'] 35 | 33,[] 36 | 34,[] 37 | 35,['OGNUSDT'] 38 | 36,"['BTCDOMUSDT', 'GMTUSDT', 'BNXUSDT']" 39 | 37,"['BTCUSDT', 'XMRUSDT', 'HOTUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 40 | 38,"['XMRUSDT', 'DASHUSDT', 'HOTUSDT', 'BTCDOMUSDT']" 41 | 39,"['BALUSDT', 'BTCDOMUSDT']" 42 | 40,"['BTCUSDT', 'SFPUSDT', 'BTCDOMUSDT']" 43 | 41,[] 44 | 42,['ATAUSDT'] 45 | 43,['THETAUSDT'] 46 | 44,[] 47 | 45,[] 48 | 46,[] 49 | 47,[] 50 | 48,"['VETUSDT', 'CTKUSDT', '1INCHUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 51 | 49,"['BCHUSDT', 'TRXUSDT', 'ETCUSDT', 'ADAUSDT', 'DOTUSDT', 'CTKUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 52 | 50,"['BCHUSDT', 'TRXUSDT', 'ADAUSDT', 'XMRUSDT', 'IOTAUSDT', 'DOTUSDT', 'UNIUSDT', 'CTKUSDT', '1INCHUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 53 | 51,"['BCHUSDT', 'XRPUSDT', 'XMRUSDT', 'IOTAUSDT', 'UNIUSDT', 'CTKUSDT', '1INCHUSDT', 'HBARUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 54 | 52,"['ZECUSDT', 'BNXUSDT']" 55 | 53,"['BCHUSDT', 'DASHUSDT', 'STORJUSDT']" 56 | 54,"['ZILUSDT', 'STORJUSDT', 'STMXUSDT']" 57 | 55,['THETAUSDT'] 58 | 56,[] 59 | 57,[] 60 | 58,[] 61 | 59,[] 62 | 60,['XMRUSDT'] 63 | 61,"['XMRUSDT', 'BTCDOMUSDT']" 64 | 62,"['BTCUSDT', 'XMRUSDT', 'FLMUSDT', 'BTCDOMUSDT']" 65 | 63,"['BTCUSDT', 'XMRUSDT', 'ZECUSDT']" 66 | 64,"['BTCUSDT', 'ETHUSDT', 'TRXUSDT', 'XMRUSDT', 'ZECUSDT', 'BALUSDT', 'RUNEUSDT', 'XEMUSDT', 'BTCDOMUSDT']" 67 | 65,"['BTCUSDT', 'ETHUSDT', 'TRXUSDT', 'XMRUSDT', 'THETAUSDT', 'MKRUSDT', 'BALUSDT', 'RUNEUSDT', 'RVNUSDT', 'BTCDOMUSDT']" 68 | 66,"['BTCUSDT', 'ETHUSDT', 'BCHUSDT', 'TRXUSDT', 'XMRUSDT', 'ATOMUSDT', 'RUNEUSDT', 'CTKUSDT', 'HBARUSDT', 'NKNUSDT', 'BTCDOMUSDT']" 69 | 67,"['XRPUSDT', 'LTCUSDT', 'ATOMUSDT', 'RUNEUSDT', 'CTKUSDT', 'NKNUSDT']" 70 | 68,"['TRXUSDT', 'XMRUSDT', 'ATOMUSDT', 'IOTAUSDT', 'CTKUSDT', 'CHRUSDT', 'BTCDOMUSDT', 'DUSKUSDT', 'APEUSDT', 'WOOUSDT']" 71 | 69,"['XMRUSDT', 'ATOMUSDT', 'IOTAUSDT', 'CTKUSDT', 'IOTXUSDT', 'WOOUSDT']" 72 | 70,"['CHRUSDT', 'WOOUSDT']" 73 | 71,"['ATOMUSDT', 'FTMUSDT', 'WOOUSDT']" 74 | 72,[] 75 | 73,[] 76 | 74,[] 77 | 75,[] 78 | 76,['HBARUSDT'] 79 | 77,[] 80 | 78,[] 81 | 79,[] 82 | 80,[] 83 | 81,['ATAUSDT'] 84 | 82,['CHRUSDT'] 85 | 83,[] 86 | 84,[] 87 | 85,[] 88 | 86,[] 89 | 87,[] 90 | 88,[] 91 | 0,"['TRXUSDT', 'CHZUSDT']" 92 | 1,"['ALGOUSDT', 'KSMUSDT', 'CHZUSDT', 'HBARUSDT']" 93 | 2,"['LTCUSDT', 'ALGOUSDT', 'CHZUSDT']" 94 | 3,['XRPUSDT'] 95 | 4,"['NEOUSDT', 'MANAUSDT']" 96 | 5,"['LTCUSDT', 'DASHUSDT', 'NEOUSDT', 'CTKUSDT', 'BNXUSDT']" 97 | 6,"['ONTUSDT', 'VETUSDT', 'CTKUSDT']" 98 | 7,['NEOUSDT'] 99 | 8,"['VETUSDT', 'ICXUSDT']" 100 | 9,"['VETUSDT', 'IOTXUSDT']" 101 | 10,"['VETUSDT', 'EGLDUSDT']" 102 | 11,['ATOMUSDT'] 103 | 12,['DENTUSDT'] 104 | 13,"['XLMUSDT', 'ZRXUSDT', 'COMPUSDT', 'DENTUSDT']" 105 | 14,"['BTCUSDT', 'ZRXUSDT']" 106 | 15,"['BTCUSDT', 'XRPUSDT', 'XLMUSDT', 'IOSTUSDT', 'ICXUSDT', 'DENTUSDT', 'HOTUSDT', 'MTLUSDT', '1000XECUSDT']" 107 | 16,"['ETHUSDT', 'DASHUSDT', 'IOSTUSDT', 'ALGOUSDT', 'EGLDUSDT', 'CTKUSDT']" 108 | 17,"['BTCUSDT', 'DASHUSDT', 'IOTAUSDT', 'EGLDUSDT', 'RVNUSDT', 'XEMUSDT']" 109 | 18,"['BTCUSDT', 'XLMUSDT', 'DASHUSDT', 'IOTAUSDT', 'IOSTUSDT', 'MTLUSDT']" 110 | 19,"['IOTAUSDT', 'ALPHAUSDT']" 111 | 20,"['ADAUSDT', 'XMRUSDT', 'ONTUSDT', 'IOTAUSDT', 'ZRXUSDT', 'OCEANUSDT', 'AXSUSDT', 'MTLUSDT']" 112 | 21,"['XRPUSDT', 'TRXUSDT', 'XLMUSDT', 'NEARUSDT', 'OCEANUSDT', 'REEFUSDT', 'BTCDOMUSDT']" 113 | 22,"['XMRUSDT', 'XTZUSDT', 'OCEANUSDT', 'ARPAUSDT']" 114 | 23,"['XRPUSDT', 'SOLUSDT', 'MATICUSDT']" 115 | 24,"['XLMUSDT', 'NEARUSDT', 'GRTUSDT']" 116 | 25,"['XRPUSDT', 'XLMUSDT', 'MTLUSDT', 'BTCDOMUSDT']" 117 | 26,"['TRXUSDT', 'XLMUSDT', 'NEOUSDT', 'ALGOUSDT', 'DOGEUSDT', 'XEMUSDT', 'COTIUSDT']" 118 | 27,"['ADAUSDT', 'VETUSDT', 'THETAUSDT', 'ALGOUSDT', 'DOGEUSDT']" 119 | 28,"['BTCUSDT', 'IOTAUSDT', 'VETUSDT', 'THETAUSDT', 'EGLDUSDT', '1INCHUSDT', 'MANAUSDT']" 120 | 29,"['TRXUSDT', 'ONTUSDT', 'DENTUSDT', 'HOTUSDT', 'DODOBUSD']" 121 | 30,"['FLMUSDT', 'HOTUSDT', 'DODOBUSD']" 122 | 31,"['THETAUSDT', 'DEFIUSDT', '1000XECUSDT']" 123 | 32,"['ZECUSDT', 'DEFIUSDT', 'CHRUSDT', '1000XECUSDT']" 124 | 33,"['TRXUSDT', 'DEFIUSDT', 'BTCDOMUSDT', '1000XECUSDT', 'WOOUSDT']" 125 | 34,"['1000XECUSDT', 'API3USDT']" 126 | 35,"['TRXUSDT', 'DASHUSDT', 'HBARUSDT', 'STMXUSDT']" 127 | 36,"['DASHUSDT', 'VETUSDT', 'IOSTUSDT', 'DOTUSDT']" 128 | 37,"['ETHUSDT', 'LINKUSDT', 'DASHUSDT', 'IOSTUSDT', 'DOTUSDT', 'BALUSDT', 'CTKUSDT', 'ALPHAUSDT']" 129 | 38,"['BTCUSDT', 'LTCUSDT', 'IOSTUSDT', 'DOTUSDT', 'BALUSDT', 'SFPUSDT', 'XEMUSDT', 'DUSKUSDT']" 130 | 39,"['BTCUSDT', 'LTCUSDT', 'XMRUSDT', 'IOSTUSDT', 'DOTUSDT', 'SFPUSDT', 'HOTUSDT']" 131 | 40,"['LTCUSDT', 'XMRUSDT', 'ZECUSDT', 'DOGEUSDT', 'TOMOUSDT', '1INCHUSDT']" 132 | 41,"['LTCUSDT', 'DASHUSDT', 'TOMOUSDT', 'ZENUSDT']" 133 | 42,"['BTCUSDT', 'THETAUSDT']" 134 | 43,"['BTCUSDT', 'TOMOUSDT', 'ALICEUSDT']" 135 | 44,['FLMUSDT'] 136 | 45,['EGLDUSDT'] 137 | 46,[] 138 | 47,[] 139 | 48,"['BCHUSDT', 'XLMUSDT', 'XMRUSDT', 'DASHUSDT', 'IOTAUSDT', 'DOTUSDT', 'XEMUSDT']" 140 | 49,"['BTCUSDT', 'XRPUSDT', 'XMRUSDT', 'DASHUSDT', 'IOTAUSDT', 'VETUSDT', 'COMPUSDT', '1INCHUSDT']" 141 | 50,"['BTCUSDT', 'XRPUSDT', 'DASHUSDT', 'ZECUSDT', 'VETUSDT', 'NEOUSDT', 'COMPUSDT', 'ZENUSDT', 'HBARUSDT', '1000XECUSDT']" 142 | 51,"['BTCUSDT', 'TRXUSDT', 'ADAUSDT', 'ZECUSDT', 'NEOUSDT', 'COMPUSDT', 'DOTUSDT', 'EGLDUSDT', 'DENTUSDT']" 143 | 52,"['BCHUSDT', 'XRPUSDT', 'XMRUSDT', 'DASHUSDT', 'IOTAUSDT', 'COMPUSDT', 'BELUSDT', '1000XECUSDT', 'GMTUSDT']" 144 | 53,"['XMRUSDT', 'ONTUSDT', '1INCHUSDT', 'STMXUSDT', 'BTCDOMUSDT', 'LPTUSDT']" 145 | 54,"['EOSUSDT', 'TRXUSDT', 'XMRUSDT', 'NEOUSDT', 'THETAUSDT', 'TOMOUSDT', 'ALICEUSDT', 'LPTUSDT']" 146 | 55,"['TRXUSDT', 'ZILUSDT', 'AAVEUSDT', 'ALICEUSDT', 'ENSUSDT']" 147 | 56,"['ETHUSDT', 'THETAUSDT', 'AAVEUSDT', 'ENSUSDT', 'DUSKUSDT']" 148 | 57,"['FLMUSDT', 'AAVEUSDT']" 149 | 58,"['MANAUSDT', 'ENSUSDT']" 150 | 59,"['BTCUSDT', 'XMRUSDT', 'HOTUSDT', 'BTCDOMUSDT']" 151 | 60,"['NEOUSDT', 'AVAXUSDT', 'ZENUSDT', 'HOTUSDT', 'BTCDOMUSDT']" 152 | 61,"['BTCUSDT', 'XRPUSDT', 'TRXUSDT', 'ZRXUSDT', 'RUNEUSDT', 'FLMUSDT', 'HOTUSDT']" 153 | 62,"['XRPUSDT', 'ZECUSDT', 'ONTUSDT', 'ZRXUSDT', 'CTKUSDT', 'CELRUSDT', 'HOTUSDT']" 154 | 63,"['XRPUSDT', 'ONTUSDT', 'ZRXUSDT', 'MKRUSDT', 'FLMUSDT', 'BELUSDT', 'HBARUSDT', 'DENTUSDT', 'HOTUSDT']" 155 | 64,"['XRPUSDT', 'XLMUSDT', 'THETAUSDT', 'MKRUSDT', 'RVNUSDT']" 156 | 65,"['XRPUSDT', 'EOSUSDT', 'ONTUSDT', 'CTKUSDT', 'HBARUSDT']" 157 | 66,"['XRPUSDT', 'EOSUSDT', 'XLMUSDT', 'IOTAUSDT', 'MKRUSDT', 'RVNUSDT']" 158 | 67,"['BTCUSDT', 'ETHUSDT', 'EOSUSDT', 'XMRUSDT', 'IOTAUSDT']" 159 | 68,"['BTCUSDT', 'ETHUSDT', 'KSMUSDT']" 160 | 69,"['BTCUSDT', 'ETHUSDT', 'TRXUSDT', 'CHRUSDT', 'BTCDOMUSDT', 'DUSKUSDT']" 161 | 70,"['XMRUSDT', 'CTKUSDT', 'ALICEUSDT', 'CTSIUSDT', 'ROSEUSDT', 'DUSKUSDT']" 162 | 71,"['XMRUSDT', 'IOTAUSDT', 'FLMUSDT', 'CTKUSDT', 'CHRUSDT', 'DUSKUSDT']" 163 | 72,[] 164 | 73,['KNCUSDT'] 165 | 74,"['ENJUSDT', 'COTIUSDT', 'HBARUSDT']" 166 | 75,"['ENJUSDT', 'HBARUSDT', 'C98USDT', 'LPTUSDT']" 167 | 76,['STORJUSDT'] 168 | 77,['ROSEUSDT'] 169 | 78,[] 170 | 79,['CHRUSDT'] 171 | 80,['ATAUSDT'] 172 | 81,"['DOGEUSDT', 'TOMOUSDT']" 173 | 82,['DODOBUSD'] 174 | 83,"['BATUSDT', 'OMGUSDT']" 175 | 84,['DASHUSDT'] 176 | 85,"['BATUSDT', 'IOSTUSDT', 'MKRUSDT']" 177 | 86,"['TRXUSDT', 'IOTAUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 178 | 87,"['TRXUSDT', 'KLAYUSDT']" 179 | 88,"['TRXUSDT', 'ICXUSDT', 'BTCDOMUSDT']" 180 | -------------------------------------------------------------------------------- /playground/rank.csv: -------------------------------------------------------------------------------- 1 | ,"4, 0" 2 | 0,"['XTZUSDT', 'TOMOUSDT']" 3 | 1,"['ALGOUSDT', 'DEFIUSDT', 'TOMOUSDT', 'HBARUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 4 | 2,"['ALGOUSDT', 'KSMUSDT', 'CHZUSDT', 'HBARUSDT']" 5 | 3,"['ALGOUSDT', 'KSMUSDT']" 6 | 4,[] 7 | 5,[] 8 | 6,"['MANAUSDT', 'BTCDOMUSDT', 'KLAYUSDT', 'BNXUSDT']" 9 | 7,['DODOBUSD'] 10 | 8,[] 11 | 9,[] 12 | 10,[] 13 | 11,[] 14 | 12,"['DASHUSDT', 'ATOMUSDT', 'KAVAUSDT', 'DOTUSDT', 'CELRUSDT']" 15 | 13,[] 16 | 14,['DOGEUSDT'] 17 | 15,[] 18 | 16,"['BTCUSDT', 'TRXUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 19 | 17,"['BTCUSDT', 'TRXUSDT', 'BALUSDT', 'EGLDUSDT', 'CTKUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 20 | 18,"['BTCUSDT', 'XRPUSDT', 'TRXUSDT', 'DASHUSDT', 'EGLDUSDT', 'XEMUSDT', 'MTLUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 21 | 19,"['XRPUSDT', 'XMRUSDT', 'DASHUSDT', 'EGLDUSDT', 'BTCDOMUSDT']" 22 | 20,[] 23 | 21,"['TRXUSDT', 'ADAUSDT', 'XMRUSDT', 'ONTUSDT', 'OCEANUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 24 | 22,"['ADAUSDT', 'XMRUSDT', 'ALGOUSDT', 'NEARUSDT', 'BNXUSDT']" 25 | 23,"['ADAUSDT', 'NEARUSDT', 'MATICUSDT']" 26 | 24,"['NEOUSDT', 'SOLUSDT', 'COTIUSDT']" 27 | 25,"['GRTUSDT', 'CTSIUSDT']" 28 | 26,"['XRPUSDT', 'XLMUSDT', 'ALGOUSDT', 'COTIUSDT', 'BTCDOMUSDT', 'CTSIUSDT']" 29 | 27,"['TRXUSDT', 'XLMUSDT', 'BTCDOMUSDT']" 30 | 28,"['BTCUSDT', 'TRXUSDT', 'XMRUSDT', 'ALGOUSDT', 'EGLDUSDT', 'DODOBUSD']" 31 | 29,"['TRXUSDT', 'XMRUSDT', 'HOTUSDT', 'DODOBUSD']" 32 | 30,"['HOTUSDT', 'DODOBUSD']" 33 | 31,"['MKRUSDT', 'FLMUSDT']" 34 | 32,"['DEFIUSDT', '1000XECUSDT']" 35 | 33,"['ZECUSDT', 'SFPUSDT', '1000XECUSDT']" 36 | 34,['API3USDT'] 37 | 35,[] 38 | 36,"['TRXUSDT', 'BNXUSDT']" 39 | 37,"['DASHUSDT', 'IOSTUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 40 | 38,"['BTCUSDT', 'XMRUSDT', 'DASHUSDT', 'IOSTUSDT', 'BALUSDT', 'ALPHAUSDT', 'HOTUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 41 | 39,"['BTCUSDT', 'DASHUSDT', 'DOTUSDT', 'SFPUSDT', 'HOTUSDT', 'BTCDOMUSDT']" 42 | 40,"['XMRUSDT', 'BALUSDT', 'SFPUSDT']" 43 | 41,"['ZECUSDT', 'TOMOUSDT', 'RENUSDT', 'BTCDOMUSDT', 'ARUSDT', 'ROSEUSDT']" 44 | 42,"['ETHUSDT', 'LTCUSDT', 'LINAUSDT', 'ATAUSDT']" 45 | 43,"['BTCUSDT', 'ATAUSDT']" 46 | 44,['THETAUSDT'] 47 | 45,[] 48 | 46,['EGLDUSDT'] 49 | 47,[] 50 | 48,[] 51 | 49,"['BCHUSDT', 'LTCUSDT', 'XLMUSDT', 'XMRUSDT', 'IOTAUSDT', 'VETUSDT', 'DOTUSDT', 'CTKUSDT', '1INCHUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 52 | 50,"['BTCUSDT', 'BCHUSDT', 'TRXUSDT', 'ADAUSDT', 'XMRUSDT', 'DASHUSDT', 'IOTAUSDT', 'VETUSDT', 'DOTUSDT', 'CTKUSDT', '1INCHUSDT', 'HBARUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 53 | 51,"['BCHUSDT', 'XRPUSDT', 'TRXUSDT', 'ADAUSDT', 'XMRUSDT', 'IOTAUSDT', 'DOTUSDT', 'EGLDUSDT', 'UNIUSDT', 'CTKUSDT', '1INCHUSDT', 'HBARUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 54 | 52,"['XRPUSDT', 'XMRUSDT', 'ZECUSDT', 'BNXUSDT']" 55 | 53,"['ZRXUSDT', 'RUNEUSDT', 'STORJUSDT', 'BELUSDT', 'LPTUSDT', 'BNXUSDT']" 56 | 54,"['BCHUSDT', 'XMRUSDT', 'DASHUSDT', 'TOMOUSDT', '1INCHUSDT', 'STMXUSDT', 'BTCDOMUSDT']" 57 | 55,"['TRXUSDT', 'ZILUSDT']" 58 | 56,"['THETAUSDT', 'BANDUSDT', 'AAVEUSDT', 'API3USDT']" 59 | 57,[] 60 | 58,[] 61 | 59,['KAVAUSDT'] 62 | 60,"['XMRUSDT', 'BTCDOMUSDT']" 63 | 61,"['TRXUSDT', 'XMRUSDT', 'RUNEUSDT', 'HOTUSDT', 'BTCDOMUSDT']" 64 | 62,"['TRXUSDT', 'XMRUSDT', 'BTCDOMUSDT']" 65 | 63,"['BTCUSDT', 'ZECUSDT', 'ONTUSDT', 'ZRXUSDT', 'FLMUSDT', 'BTCDOMUSDT']" 66 | 64,"['BTCUSDT', 'XRPUSDT', 'XMRUSDT', 'ZECUSDT', 'BALUSDT', 'DENTUSDT', 'HOTUSDT']" 67 | 65,"['BTCUSDT', 'ETHUSDT', 'TRXUSDT', 'XMRUSDT', 'ZECUSDT', 'THETAUSDT', 'MKRUSDT', 'BALUSDT', 'RUNEUSDT', 'RVNUSDT', 'BTCDOMUSDT']" 68 | 66,"['BTCUSDT', 'ETHUSDT', 'BCHUSDT', 'XRPUSDT', 'TRXUSDT', 'XLMUSDT', 'XMRUSDT', 'ATOMUSDT', 'MKRUSDT', 'RUNEUSDT', 'CTKUSDT', 'RVNUSDT', 'HBARUSDT', 'NKNUSDT', 'BTCDOMUSDT']" 69 | 67,"['BTCUSDT', 'ETHUSDT', 'LTCUSDT', 'XMRUSDT', 'ATOMUSDT', 'IOTAUSDT', 'RUNEUSDT', 'CTKUSDT', 'HBARUSDT', 'NKNUSDT']" 70 | 68,"['ATOMUSDT', 'IOTAUSDT', 'SXPUSDT', 'KSMUSDT', 'CTKUSDT', 'DUSKUSDT', 'WOOUSDT']" 71 | 69,"['BTCUSDT', 'XMRUSDT', 'ATOMUSDT', 'IOTAUSDT', 'KSMUSDT', 'CTKUSDT', 'CHRUSDT', 'BTCDOMUSDT', 'DUSKUSDT', 'APEUSDT', 'WOOUSDT']" 72 | 70,"['XMRUSDT', 'UNIUSDT', 'IOTXUSDT', 'AUDIOUSDT', 'ARPAUSDT']" 73 | 71,"['FLMUSDT', 'CHRUSDT', 'CELOUSDT', 'CTSIUSDT', 'WOOUSDT']" 74 | 72,[] 75 | 73,[] 76 | 74,[] 77 | 75,['ENJUSDT'] 78 | 76,['ENJUSDT'] 79 | 77,['HBARUSDT'] 80 | 78,[] 81 | 79,[] 82 | 80,[] 83 | 81,[] 84 | 82,[] 85 | 83,[] 86 | 84,[] 87 | 85,[] 88 | 86,"['TRXUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 89 | 87,"['TRXUSDT', 'BTCDOMUSDT', 'BNXUSDT']" 90 | 88,"['TRXUSDT', 'BTCDOMUSDT', 'KLAYUSDT']" 91 | 89,[] 92 | 90,[] 93 | -------------------------------------------------------------------------------- /quantlib.egg-info/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.1 2 | Name: quantlib 3 | Version: 0.1 4 | Summary: code lib by Larry 5 | Home-page: # 6 | Author: Larry 7 | Author-email: 8 | -------------------------------------------------------------------------------- /quantlib.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | README.md 2 | setup.py 3 | quantlib/__init__.py 4 | quantlib/backtest_utils.py 5 | quantlib/crypto_data_utils.py 6 | quantlib/crypto_format_utils.py 7 | quantlib/data_utils.py 8 | quantlib/diagnostics_utils.py 9 | quantlib/general_utils.py 10 | quantlib/indicators_cal.py 11 | quantlib/printer_utils.py 12 | quantlib.egg-info/PKG-INFO 13 | quantlib.egg-info/SOURCES.txt 14 | quantlib.egg-info/dependency_links.txt 15 | quantlib.egg-info/not-zip-safe 16 | quantlib.egg-info/requires.txt 17 | quantlib.egg-info/top_level.txt -------------------------------------------------------------------------------- /quantlib.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /quantlib.egg-info/not-zip-safe: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /quantlib.egg-info/requires.txt: -------------------------------------------------------------------------------- 1 | opencv-python 2 | -------------------------------------------------------------------------------- /quantlib.egg-info/top_level.txt: -------------------------------------------------------------------------------- 1 | quantlib 2 | -------------------------------------------------------------------------------- /quantlib/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/quantlib/.DS_Store -------------------------------------------------------------------------------- /quantlib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/quantlib/__init__.py -------------------------------------------------------------------------------- /quantlib/backtest_utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | def get_backtest_day_stats(portfolio_df, instruments, date, date_prev, date_idx, historical_data, is_crypto=False): 5 | pnl = 0 #pnl for the day 6 | nominal_ret = 0 #nominal returns 7 | 8 | #we can either use vector operations to calculate returns or calculate one by one 9 | #the former is faster, but the latter is clearer and easier to interpret 10 | 11 | for inst in instruments: 12 | previous_holdings = portfolio_df.loc[date_idx - 1, "{} units".format(inst)] 13 | if previous_holdings != 0: 14 | price_change = historical_data.loc[date, "{} close".format(inst)] - historical_data.loc[date_prev, "{} close".format(inst)] 15 | if is_crypto: 16 | dollar_change = price_change 17 | else: 18 | dollar_change = unit_val_change(inst, price_change, historical_data, date_prev) 19 | dollar_change = price_change 20 | inst_pnl = dollar_change * previous_holdings 21 | pnl += inst_pnl 22 | nominal_ret += portfolio_df.loc[date_idx - 1, "{} w".format(inst)] * historical_data.loc[date, "{} % ret".format(inst)] 23 | 24 | capital_ret = nominal_ret * portfolio_df.loc[date_idx - 1, "leverage"] 25 | portfolio_df.loc[date_idx, "capital"] = portfolio_df.loc[date_idx - 1, "capital"] + pnl 26 | portfolio_df.loc[date_idx, "daily pnl"] = pnl 27 | portfolio_df.loc[date_idx, "nominal ret"] = nominal_ret 28 | portfolio_df.loc[date_idx, "capital ret"] = capital_ret 29 | return portfolio_df, pnl, capital_ret 30 | 31 | #https://hangukquant.substack.com/p/volatility-targeting-the-strategy 32 | def get_strat_scaler(portfolio_df, lookback, vol_target, idx, default): 33 | capital_ret_history = portfolio_df.loc[:idx].dropna().tail(lookback)["capital ret"] 34 | strat_scaler_history = portfolio_df.loc[:idx].dropna().tail(lookback)["strat scalar"] 35 | if len(capital_ret_history) == lookback: 36 | #enough data, then increase or decrease the scalar based on empirical vol of the strategy equity curve relative to target vol 37 | annualized_vol = capital_ret_history.std() * np.sqrt(253) #annualise the vol from daily vol 38 | scalar_hist_avg = np.mean(strat_scaler_history) 39 | strat_scalar = scalar_hist_avg * vol_target / annualized_vol 40 | return strat_scalar 41 | else: 42 | #not enough data, just return a default value 43 | return default 44 | 45 | #How much is the price change in contract x worth in base currency USD? 46 | """ 47 | from_prod: instrument traded, e.g. HK33_HKD 48 | val_change: change in price quote 49 | """ 50 | def unit_val_change(from_prod, val_change, historical_data, date): 51 | is_denominated = len(from_prod.split("_")) == 2 52 | if not is_denominated: 53 | return val_change #assume USD denominated, e.g. AAPL 54 | elif is_denominated and from_prod.split("_")[1] == "USD": 55 | return val_change #USD denominated, e.g. AAPL_USD, EUR_USD 56 | else: 57 | #e.g. HK33_HKD, USD_JPY (X_Y) 58 | #take delta price * (Y_USD) = price change in USD terms 59 | return val_change * historical_data.loc[date, "{}_USD close".format(from_prod.split("_")[1])] 60 | 61 | #how much is 1 contract `worth`? 62 | def unit_dollar_value(from_prod, historical_data, date): 63 | is_denominated = len(from_prod.split("_")) == 2 64 | if not is_denominated: 65 | return historical_data.loc[date, "{} close".format(from_prod)] #e.g. AAPL units is worth the price of 1 AAPL unit 66 | if is_denominated and from_prod.split("_")[0] == "USD": 67 | return 1 #e.g. USD_JPY unit is worth 1 USD! 68 | if is_denominated and not from_prod.split("_")[0] == "USD": 69 | #e.g.HK33_HKD, EUR_USD, (X_Y) 70 | #then you want to take the price change in the denominated currency, which is unit_price * Y_USD 71 | unit_price = historical_data.loc[date, "{} close".format(from_prod)] 72 | fx_inst = "{}_{}".format(from_prod.split("_")[1], "USD") 73 | fx_quote = 1 if fx_inst == "USD_USD" else historical_data.loc[date, "{} close".format(fx_inst)] 74 | return unit_price * fx_quote 75 | 76 | 77 | def set_leverage_cap(portfolio_df, instruments, date, idx, nominal_tot, leverage_cap, historical_data): 78 | leverage = nominal_tot / portfolio_df.loc[idx, "capital"] 79 | if leverage > leverage_cap: 80 | new_nominals = 0 81 | leverage_scalar = leverage_cap / leverage 82 | for inst in instruments: 83 | newpos = portfolio_df.loc[idx, "{} units".format(inst)] * leverage_scalar 84 | portfolio_df.loc[idx, "{} units".format(inst)] = newpos 85 | if newpos != 0: 86 | new_nominals += abs(newpos * unit_dollar_value(inst, historical_data, date)) 87 | return new_nominals 88 | else: 89 | return nominal_tot 90 | 91 | #get some statistics from the portfolio df 92 | def kpis(df): 93 | portfolio_df = df.copy() 94 | portfolio_df["cum ret"] = (1 + portfolio_df["capital ret"]).cumprod() 95 | portfolio_df["drawdown"] = portfolio_df["cum ret"] / portfolio_df["cum ret"].cummax() - 1 96 | sharpe = portfolio_df["capital ret"].mean() / portfolio_df["capital ret"].std() * np.sqrt(253) 97 | drawdown_max = portfolio_df["drawdown"].min() * 100 98 | volatility = portfolio_df["capital ret"].std() * np.sqrt(253) * 100 #annualised percent vol 99 | return portfolio_df, sharpe, drawdown_max, volatility -------------------------------------------------------------------------------- /quantlib/crypto_data_utils.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import time 3 | import pandas as pd 4 | 5 | BINANCE_BASE_URL = "https://fapi.binance.com" 6 | 7 | 8 | def get_symbols(): 9 | url = "/fapi/v1/exchangeInfo" 10 | url = BINANCE_BASE_URL + url 11 | try: 12 | symbols = requests.get(url).json()["symbols"] 13 | symbols = [x["symbol"] for x in symbols] 14 | except: 15 | raise Exception("Could be the problem of region! Try another location") 16 | 17 | # Remove some BUSD pairs 18 | remove_list = [] 19 | for symbol in symbols: 20 | if "BUSD" in symbol and symbol[:-4] + "USDT" in symbols: 21 | remove_list.append(symbol) 22 | if "_" in symbol or "USDC" in symbol: 23 | remove_list.append(symbol) 24 | symbols = [x for x in symbols if x not in remove_list] 25 | 26 | return symbols 27 | 28 | def get_symbols_from_df(df): 29 | instruments = [] 30 | for col in df.columns: 31 | inst = col.split(" ")[0] 32 | if "USD" in inst and inst not in instruments: 33 | instruments.append(inst) 34 | return instruments 35 | 36 | 37 | def sleep_if_big_limit(limit): 38 | if limit >= 1000: 39 | time.sleep(0.35) 40 | 41 | def get_crypto_futures_df(interval='4h', limit=1000, end_time=None): 42 | """Get all tradable crypto data from binance""" 43 | url = "/fapi/v1/klines" 44 | url = BINANCE_BASE_URL + url 45 | 46 | columns = ["open_time", "open","high","low","close","volume","close_time","quote_volume","count","taker_buy_volume","taker_buy_quote_volume","ignore"] 47 | symbols = get_symbols() 48 | ohlcvs = {} 49 | for symbol in symbols: 50 | sleep_if_big_limit(limit) # Prevent exceeding the API limit 51 | data = { 52 | "symbol": symbol, 53 | "interval": interval, 54 | "limit": str(limit) 55 | } 56 | if end_time: 57 | data["endTime"] = end_time 58 | response = requests.get(url, params=data).json() 59 | ohlcvs[symbol] = (pd.DataFrame(response, columns=columns, dtype=float) 60 | .drop(["close_time", "ignore", "volume", "taker_buy_volume"], axis=1) 61 | .set_index("open_time") 62 | ) 63 | print (ohlcvs[symbol]) 64 | 65 | df = pd.DataFrame(index=ohlcvs["BTCUSDT"].index) 66 | instruments = list(ohlcvs.keys()) 67 | 68 | for inst in instruments: 69 | inst_df = ohlcvs[inst] 70 | cols = list(map(lambda x: f"{inst} {x}", inst_df.columns)) 71 | df[cols] = inst_df 72 | 73 | if not end_time: 74 | df.to_excel(f"crypto_ohlv_{interval}.xlsx") 75 | else: 76 | df.to_excel(f"crypto_ohlv_{interval}_{end_time}.xlsx") 77 | return df, instruments 78 | 79 | 80 | def extend_dataframe(traded, df, interval='4h'): 81 | df.index = pd.to_datetime(df.index, unit='ms') 82 | target_cols = [col for col in df.columns if col.split(' ')[0] in traded] 83 | historical_data = df.copy() 84 | historical_data = historical_data[target_cols] 85 | historical_data.fillna(method="ffill", inplace=True) 86 | historical_data.fillna(method="bfill", inplace=True) 87 | 88 | for inst in traded: 89 | historical_data[f"{inst} avg trade size"] = historical_data[f"{inst} quote_volume"] / historical_data[f"{inst} count"] 90 | historical_data[f"{inst} taker %"] = historical_data[f"{inst} taker_buy_quote_volume"] / historical_data[f"{inst} quote_volume"] 91 | historical_data[f"{inst} % ret"] = historical_data[f"{inst} close"] / historical_data[f"{inst} close"].shift(1) - 1 92 | historical_data[f"{inst} % ret vol"] = historical_data[f"{inst} % ret"].rolling(25).std() 93 | # active if the close price are not the same between two days 94 | historical_data[f"{inst} active"] = historical_data[f"{inst} close"] != historical_data[f"{inst} close"].shift(1) 95 | 96 | #historical_data.to_excel(f"crypto_historical_{interval}.xlsx") 97 | return historical_data 98 | 99 | 100 | if __name__ == "__main__": 101 | df, instruments = get_crypto_futures_df(interval='4h', limit=1400, end_time=1656691200000) # max limit is 1500 102 | #historical_data = extend_dataframe(instruments, df, interval='1h') -------------------------------------------------------------------------------- /quantlib/crypto_format_utils.py: -------------------------------------------------------------------------------- 1 | """Crypto format utils functions""" 2 | 3 | def format_quantity(quantity, price): 4 | if price < 100: 5 | quantity = int("{:.0f}".format(quantity)) 6 | elif price < 250: 7 | quantity = float("{:.1f}".format(quantity)) 8 | elif price < 10000: 9 | quantity = float("{:.2f}".format(quantity)) 10 | else: 11 | quantity = float("{:.3f}".format(quantity)) 12 | 13 | return quantity 14 | 15 | def format_price(stop_price): 16 | 17 | if stop_price < 0.01: 18 | stop_price = float("{:.5f}".format(stop_price)) 19 | elif stop_price < 0.5: 20 | stop_price = float("{:.4f}".format(stop_price)) 21 | elif stop_price < 10: 22 | stop_price = float("{:.3f}".format(stop_price)) 23 | elif stop_price < 200: 24 | stop_price = float("{:.2f}".format(stop_price)) 25 | else: 26 | stop_price = float("{:.1f}".format(stop_price)) 27 | 28 | return stop_price -------------------------------------------------------------------------------- /quantlib/data_utils.py: -------------------------------------------------------------------------------- 1 | #Install Python > 3,6 2 | #Install VS Code 3 | 4 | #Install Pandas python3 -m pip install pandas 5 | #Install Pandas python3 -m pip install yfinance 6 | 7 | 8 | #First, let us obtain stickers in the SP500. (data part) 9 | 10 | import requests 11 | import datetime 12 | import pandas as pd 13 | import yfinance as yf #python3 -m pip install yFinance 14 | from bs4 import BeautifulSoup #python3 -m pip insall bs4 15 | 16 | def get_sp500_instruments(): 17 | res = requests.get("https://en.wikipedia.org/wiki/List_of_S%26P_500_companies") 18 | soup = BeautifulSoup(res.content,'lxml') 19 | table = soup.find_all('table')[0] 20 | df = pd.read_html(str(table)) 21 | return list(df[0]["Symbol"]) 22 | 23 | 24 | def get_sp500_df(): 25 | symbols = get_sp500_instruments() 26 | #to save time, let us perform ohlcv retrieval for 30 stocks 27 | symbols = symbols[:30] 28 | ohlcvs = {} 29 | for symbol in symbols: 30 | symbol_df = yf.Ticker(symbol).history(period="10y") #this gives us the OHLCV Dividends + Stock Splits 31 | #we are interested in the OHLCV mainly, let's rename them 32 | ohlcvs[symbol] = symbol_df[["Open", "High", "Low", "Close", "Volume"]].rename( 33 | columns={ 34 | "Open": "open", 35 | "High": "high", 36 | "Low": "low", 37 | "Close": "close", 38 | "Volume": "volume" 39 | } 40 | ) 41 | print(symbol) 42 | print(ohlcvs[symbol]) #we can now get the data that we want inside a nicely formatted df 43 | 44 | #now, we want to put that all into a single dataframe. 45 | #since the columns need to be unique to identify the instrument, we want to add an identifier. 46 | #let's steal the GOOGL index as our dataframe index 47 | df = pd.DataFrame(index=ohlcvs["GOOGL"].index) 48 | df.index.name = "date" 49 | instruments = list(ohlcvs.keys()) 50 | 51 | for inst in instruments: 52 | inst_df = ohlcvs[inst] 53 | columns = list(map(lambda x: "{} {}".format(inst, x), inst_df.columns)) #this tranforms open, high... to AAPL open , AAPL high and so on 54 | df[columns] = inst_df 55 | 56 | return df, instruments 57 | 58 | #take an ohlcv df and add some other statistics 59 | def extend_dataframe(traded, df, fx_codes): 60 | df.index = pd.Series(df.index).apply(lambda x: format_date(x)) 61 | open_cols = list(map(lambda x: str(x) + " open", traded)) 62 | high_cols = list(map(lambda x: str(x) + " high", traded)) 63 | low_cols = list(map(lambda x: str(x) + " low", traded)) 64 | close_cols = list(map(lambda x: str(x) + " close", traded)) 65 | volume_cols = list(map(lambda x: str(x) + " volume", traded)) 66 | historical_data = df.copy() 67 | historical_data = historical_data[open_cols + high_cols + low_cols + close_cols + volume_cols] #get a df with ohlcv for all traded instruments 68 | historical_data.fillna(method="ffill", inplace=True) #fill missing data by first forward filling data, such that [] [] [] a b c [] [] [] becomes [] [] [] a b c c c c 69 | historical_data.fillna(method="bfill", inplace=True) #fill missing data by backward filling data, such that [] [] [] a b c c c c becomes a a a a b c c c c 70 | for inst in traded: 71 | historical_data["{} % ret".format(inst)] = historical_data["{} close".format(inst)] / historical_data["{} close".format(inst)].shift(1) - 1 #close to close return statistic 72 | historical_data["{} % ret vol".format(inst)] = historical_data["{} % ret".format(inst)].rolling(25).std() #historical rolling standard deviation of returns as realised volatility proxy 73 | #test if stock is actively trading by using rough measure of non-zero price change from previous time step 74 | historical_data["{} active".format(inst)] = historical_data["{} close".format(inst)] != historical_data["{} close".format(inst)].shift(1) 75 | 76 | if is_fx(inst, fx_codes): 77 | inst_rev = "{}_{}".format(inst.split("_")[1], inst.split("_")[0]) 78 | #fill in inverse fx quotes and statistics 79 | historical_data["{} close".format(inst_rev)] = 1 / historical_data["{} close".format(inst)] 80 | historical_data["{} % ret".format(inst_rev)] = historical_data["{} close".format(inst_rev)] / historical_data["{} close".format(inst_rev)].shift(1) - 1 81 | historical_data["{} % ret vol".format(inst_rev)] = historical_data["{} % ret".format(inst_rev)].rolling(25).std() 82 | historical_data["{} active".format(inst_rev)] = historical_data["{} close".format(inst_rev)] != historical_data["{} close".format(inst_rev)].shift(1) 83 | return historical_data 84 | 85 | def is_fx(inst, fx_codes): 86 | return len(inst.split("_")) == 2 and inst.split("_")[0] in fx_codes and inst.split("_")[1] in fx_codes 87 | 88 | def format_date(date): 89 | #convert 2012-02-06 00:00:00 >> datetime.date(2012, 2, 6) 90 | yymmdd = list(map(lambda x: int(x), str(date).split(" ")[0].split("-"))) 91 | return datetime.date(yymmdd[0], yymmdd[1], yymmdd[2]) 92 | 93 | 94 | """ 95 | Note there are multiple ways to fill missing data, depending on your requirements and purpose 96 | Some options 97 | 1. Ffill -> bfill 98 | 2. Brownian motion/bridge 99 | 3. GARCH/GARCH Copula et cetera 100 | 4. Synthetic Data, such as GAN and Stochastic Volatility Neural Networks 101 | 102 | The choices differ for your requirements . For instance, in backtesting you might favor (1), while in training neural models you might favor (4). 103 | 104 | Note that the data cycle can be very complicated, with entire research teams dedicated to obtaining, processing and extracting signals from structured/unstructured data. 105 | What we show today barely scratches the surface of the entire process, since we are dealing with well behaved data that is structured and already cleaned for us by Yahoo Finance API. 106 | """ -------------------------------------------------------------------------------- /quantlib/diagnostics_utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import seaborn as sns 4 | import matplotlib.pyplot as plt 5 | 6 | import quantlib.general_utils as gu 7 | from quantlib.backtest_utils import kpis 8 | 9 | 10 | def save_backtests(portfolio_df, instruments, brokerage_used, sysname, path="./backtests"): 11 | portfolio_df, sharpe, drawdown_max, vol_ann = kpis(df=portfolio_df) 12 | annotation = "{}: \nSharpe: {} \nDrawdown: {}\nVolatility: {}\n".format( 13 | sysname, round(sharpe, 2), round(drawdown_max, 2), round(vol_ann, 2) 14 | ) 15 | ax = sns.lineplot(data=portfolio_df["cum ret"], linewidth=2.5, palette="deep") 16 | ax.annotate( 17 | annotation, xy=(0.2, 0.8), xycoords="axes fraction", bbox=dict(boxstyle="round,pad=0.5", fc="white", alpha=0.3), ha="center", va="center", family="serif", size="8" 18 | ) 19 | plt.title("Cumulative Returns") 20 | plt.savefig("{}/{}_{}.png".format(path, brokerage_used, sysname), bbox_inches="tight") 21 | plt.close() 22 | portfolio_df.to_excel("{}/{}_{}.xlsx".format(path, brokerage_used, sysname)) 23 | gu.save_file("{}/{}_{}.obj".format(path, brokerage_used, sysname), portfolio_df) 24 | 25 | def save_diagnostics(portfolio_df, instruments, brokerage_used, sysname, path="./diagnostics"): 26 | for inst in instruments: 27 | portfolio_df["{} w".format(inst)].plot() 28 | plt.title("Instrument Weights") 29 | plt.savefig("{}/{}/{}_weights.png".format(path, sysname, brokerage_used), bbox_inches="tight") 30 | plt.close() 31 | 32 | portfolio_df["leverage"].plot() 33 | plt.title("Portfolio Leverage") 34 | plt.savefig("{}/{}/{}_leverage.png".format(path, sysname, brokerage_used), bbox_inches="tight") 35 | plt.close() 36 | 37 | plt.scatter(portfolio_df.index, portfolio_df["capital ret"] * 100) 38 | plt.title("Daily Return Scatter Plot") 39 | plt.savefig("{}/{}/{}_scatter.png".format(path, sysname, brokerage_used), bbox_inches="tight") 40 | plt.close() 41 | 42 | #histogram plot, etc etc -------------------------------------------------------------------------------- /quantlib/general_utils.py: -------------------------------------------------------------------------------- 1 | #this is utility file for perforing simple tasks 2 | 3 | #python3 -m pip install pickle 4 | 5 | import pickle 6 | 7 | def save_file(path, obj): 8 | try: 9 | with open(path, "wb") as fp: #write bytes 10 | pickle.dump(obj, fp) 11 | except Exception as err: 12 | #do some error handling 13 | print(err) 14 | 15 | def load_file(path): 16 | try: 17 | with open(path, "rb") as fp: #load bytes 18 | return pickle.load(fp) 19 | except Exception as err: 20 | #do some error handling 21 | print(err) 22 | -------------------------------------------------------------------------------- /quantlib/indicators_cal.py: -------------------------------------------------------------------------------- 1 | """ 2 | A calculator for indicators and other functionalities 3 | """ 4 | 5 | #we are going to use another dependency, called the technical analysis library (talib) 6 | #Google: how to install talib (on Mac using brew) and (on Windows downloading the relevant file - do note that your python version needs to match with the downloaded whl file - then run pip install) 7 | 8 | import talib 9 | import numpy as np 10 | import pandas as pd 11 | 12 | def adx_series(high, low, close, n): 13 | return talib.ADX(high, low, close, timeperiod=n) 14 | 15 | def ema_series(series, n): 16 | return talib.EMA(series, timeperiod=n) 17 | 18 | def sma_series(series, n): 19 | return talib.SMA(series, timeperiod=n) 20 | 21 | 22 | """ 23 | The reason why we do this in a separate library is due to design principle, such as separation of concerns. 24 | Other modules are not concerned with how the logic for EMA/SMA is implemented, it is just interested in getting the SMA. 25 | for instance, we can change the implementation of the sma_series function to 26 | 27 | return series.rolling(n).mean() 28 | 29 | this means that if we were to change the implementation inside the sma_series function, no other component of the trading system needs to be `concerned` with this change, 30 | as long as the specification is met. 31 | 32 | suppose we did talib.SMA everywhere instead of using the sma_series function, then when we change the implementation, we would need to edit the code everywhere the function 33 | is used, and this means your code is not scalable! 34 | """ -------------------------------------------------------------------------------- /quantlib/printer_utils.py: -------------------------------------------------------------------------------- 1 | #python3 -m pip install termcolor 2 | import enum 3 | from termcolor import colored, cprint 4 | 5 | class Printer(): 6 | 7 | @staticmethod 8 | def pretty(left="", centre="", right="", color=None, highlight=None): 9 | formatted = "{:<20}{:^10}{:>10}".format(left, centre, right) 10 | if color != None and highlight != None: 11 | color_format = colored(formatted, color=color.value, on_color=highlight.value) 12 | elif color != None: 13 | color_format = colored(formatted, color=color.value) 14 | elif highlight != None: 15 | color_format = colored(formatted, on_color=highlight.value) 16 | else: 17 | color_format = formatted 18 | cprint(color_format) 19 | 20 | 21 | class _Colors(enum.Enum): 22 | GREY = "grey" 23 | RED = "red" 24 | GREEN = "green" 25 | YELLOW = "yellow" 26 | PURPLE = "purple" 27 | BLUE = "cyan" 28 | WHITE = "white" 29 | 30 | class _Highlights(enum.Enum): 31 | GREY = "on_grey" 32 | RED = "on_red" 33 | GREEN = "on_green" 34 | YELLOW = "on_yellow" 35 | PURPLE = "on_purple" 36 | BLUE = "on_cyan" 37 | WHITE = "on_white" -------------------------------------------------------------------------------- /script.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | result = [] 4 | 5 | while len(result) < 17: 6 | x, y = random.choices(range(100), k=2) 7 | if x < y and [x, y] not in result: 8 | result.append([x, y]) 9 | 10 | print (result) 11 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools #python3 -m pip install setuptools 2 | 3 | #1. Create a folder for your private code library 4 | #2. Create an __init__ py file inside the code library 5 | #3. Create a setup file outside the private code library 6 | #4. Now you can add code files inside the quantlib folder and use it as a package like any other! (pip install using developement mode) >> python3 -m pip install -e. 7 | 8 | setuptools.setup( 9 | name="quantlib", 10 | version="0.1", 11 | description="code lib by Larry", 12 | url="#", 13 | author="Larry", 14 | install_requires=["opencv-python"], 15 | author_email="", 16 | packages=setuptools.find_packages(), 17 | zip_safe=False 18 | ) #do go and read what these parameters mean! -------------------------------------------------------------------------------- /subsystems/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/subsystems/.DS_Store -------------------------------------------------------------------------------- /subsystems/LBMOM/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/subsystems/LBMOM/.DS_Store -------------------------------------------------------------------------------- /subsystems/LBMOM/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "fx": [], 3 | "commodities": [], 4 | "metals": [], 5 | 6 | "crypto": [ 7 | "LTC_USD", 8 | "BTC_USD", 9 | "ETH_USD", 10 | "BCH_USD" 11 | ], 12 | 13 | "indices": [ 14 | "HK33_HKD", 15 | "FR40_EUR", 16 | "IN50_USD", 17 | "JP225_USD", 18 | "CN50_USD", 19 | "EU50_EUR", 20 | "TWIX_USD", 21 | "US2000_USD", 22 | "UK100_GBP", 23 | "SPX500_USD", 24 | "JP225Y_JPY", 25 | "ESPIX_EUR", 26 | "NAS100_USD", 27 | "NL25_EUR", 28 | "SG30_SGD", 29 | "AU200_AUD", 30 | "CHINAH_HKD", 31 | "CH20_CHF", 32 | "US30_USD", 33 | "DE30_EUR" 34 | ], 35 | 36 | "bonds": [ 37 | "DE10YB_EUR", 38 | "USB02Y_USD", 39 | "USB05Y_USD", 40 | "USB10Y_USD", 41 | "UK10YB_GBP", 42 | "USB30Y_USD" 43 | ], 44 | 45 | "fx_codes": [ 46 | "HKD", 47 | "HUF", 48 | "GBP", 49 | "CNH", 50 | "NOK", 51 | "EUR", 52 | "TRY", 53 | "SGD", 54 | "CZK", 55 | "USD", 56 | "ZAR", 57 | "INR", 58 | "SEK", 59 | "JPY", 60 | "CAD", 61 | "NZD", 62 | "THB", 63 | "PLN", 64 | "AUD", 65 | "CHF", 66 | "DKK", 67 | "MXN" 68 | ] 69 | } -------------------------------------------------------------------------------- /subsystems/LBMOM/dwx_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "equities": [ 3 | "MPC", 4 | "MRK", 5 | "MS", 6 | "NEE", 7 | "NEM", 8 | "NKE", 9 | "NOC", 10 | "NSC", 11 | "OKE", 12 | "OMC", 13 | "ORCL", 14 | "OXY", 15 | "PANW", 16 | "PFE", 17 | "PG", 18 | "PGR", 19 | "PH", 20 | "PLD", 21 | "PM", 22 | "PNC", 23 | "PPG", 24 | "PRU", 25 | "PSA", 26 | "PXD" 27 | ], 28 | 29 | "fx": [], 30 | "commodities": [], 31 | "metals": [], 32 | 33 | "crypto": [ 34 | ], 35 | 36 | "indices": [ 37 | ], 38 | 39 | "bonds": [ 40 | ], 41 | 42 | "fx_codes": [ 43 | "TRY", 44 | "CHF", 45 | "EUR", 46 | "AUD", 47 | "SEK", 48 | "GBP", 49 | "MXN", 50 | "NOK", 51 | "JPY", 52 | "NZD", 53 | "USD", 54 | "CAD", 55 | "SGD" 56 | ] 57 | } -------------------------------------------------------------------------------- /subsystems/LBMOM/oan_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "equities": [], 3 | "fx": [], 4 | "commodities": [], 5 | "metals": [], 6 | 7 | "crypto": [ 8 | "LTC_USD", 9 | "BTC_USD", 10 | "ETH_USD", 11 | "BCH_USD" 12 | ], 13 | 14 | "indices": [], 15 | 16 | "bonds": [], 17 | 18 | "fx_codes": [ 19 | "HKD", 20 | "HUF", 21 | "GBP", 22 | "CNH", 23 | "NOK", 24 | "EUR", 25 | "TRY", 26 | "SGD", 27 | "CZK", 28 | "USD", 29 | "ZAR", 30 | "INR", 31 | "SEK", 32 | "JPY", 33 | "CAD", 34 | "NZD", 35 | "THB", 36 | "PLN", 37 | "AUD", 38 | "CHF", 39 | "DKK", 40 | "MXN" 41 | ] 42 | } -------------------------------------------------------------------------------- /subsystems/LBMOM/oan_config_backup.json: -------------------------------------------------------------------------------- 1 | { 2 | "equities": [], 3 | "fx": [], 4 | "commodities": [], 5 | "metals": [], 6 | 7 | "crypto": [ 8 | "LTC_USD", 9 | "BTC_USD", 10 | "ETH_USD", 11 | "BCH_USD" 12 | ], 13 | 14 | "indices": [ 15 | "HK33_HKD", 16 | "FR40_EUR", 17 | "IN50_USD", 18 | "JP225_USD", 19 | "CN50_USD", 20 | "EU50_EUR", 21 | "TWIX_USD", 22 | "US2000_USD", 23 | "UK100_GBP", 24 | "SPX500_USD", 25 | "JP225Y_JPY", 26 | "ESPIX_EUR", 27 | "NAS100_USD", 28 | "NL25_EUR", 29 | "SG30_SGD", 30 | "AU200_AUD", 31 | "CHINAH_HKD", 32 | "CH20_CHF", 33 | "US30_USD", 34 | "DE30_EUR" 35 | ], 36 | 37 | "bonds": [ 38 | "DE10YB_EUR", 39 | "USB02Y_USD", 40 | "USB05Y_USD", 41 | "USB10Y_USD", 42 | "UK10YB_GBP", 43 | "USB30Y_USD" 44 | ], 45 | 46 | "fx_codes": [ 47 | "HKD", 48 | "HUF", 49 | "GBP", 50 | "CNH", 51 | "NOK", 52 | "EUR", 53 | "TRY", 54 | "SGD", 55 | "CZK", 56 | "USD", 57 | "ZAR", 58 | "INR", 59 | "SEK", 60 | "JPY", 61 | "CAD", 62 | "NZD", 63 | "THB", 64 | "PLN", 65 | "AUD", 66 | "CHF", 67 | "DKK", 68 | "MXN" 69 | ] 70 | } -------------------------------------------------------------------------------- /subsystems/LSMOM/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/subsystems/LSMOM/.DS_Store -------------------------------------------------------------------------------- /subsystems/LSMOM/dwx_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "fx": [ 3 | "AUD_USD", 4 | "EUR_USD", 5 | "GBP_USD", 6 | "NZD_USD", 7 | "USD_CAD", 8 | "USD_CHF", 9 | "USD_JPY", 10 | "USD_MXN", 11 | "USD_NOK", 12 | "USD_SEK", 13 | "USD_SGD", 14 | "USD_TRY" 15 | ], 16 | 17 | "metals": [ 18 | ], 19 | 20 | "commodities": [ 21 | "XAG_USD", 22 | "XAU_USD", 23 | "XNG_USD", 24 | "XTI_USD" 25 | ], 26 | 27 | "crypto": [ 28 | ], 29 | 30 | "indices": [ 31 | ], 32 | 33 | "bonds": [ 34 | ], 35 | 36 | "fx_codes": [ 37 | "TRY", 38 | "CHF", 39 | "EUR", 40 | "AUD", 41 | "SEK", 42 | "GBP", 43 | "MXN", 44 | "NOK", 45 | "JPY", 46 | "NZD", 47 | "USD", 48 | "CAD", 49 | "SGD" 50 | 51 | ] 52 | } -------------------------------------------------------------------------------- /subsystems/LSMOM/oan_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "fx": [], 3 | 4 | "metals": [ 5 | "XPD_USD", 6 | "XAU_USD", 7 | "XPT_USD", 8 | "XAG_USD" 9 | ], 10 | 11 | "commodities": [ 12 | "BCO_USD", 13 | "NATGAS_USD", 14 | "XCU_USD", 15 | "WTICO_USD", 16 | "SUGAR_USD", 17 | "CORN_USD", 18 | "WHEAT_USD", 19 | "SOYBN_USD" 20 | ], 21 | 22 | "crypto": [ 23 | ], 24 | 25 | "indices": [ 26 | ], 27 | 28 | "bonds": [ 29 | "DE10YB_EUR", 30 | "USB02Y_USD", 31 | "USB05Y_USD", 32 | "USB10Y_USD", 33 | "UK10YB_GBP", 34 | "USB30Y_USD" 35 | ], 36 | 37 | "fx_codes": [ 38 | "HKD", 39 | "HUF", 40 | "GBP", 41 | "CNH", 42 | "NOK", 43 | "EUR", 44 | "TRY", 45 | "SGD", 46 | "CZK", 47 | "USD", 48 | "ZAR", 49 | "INR", 50 | "SEK", 51 | "JPY", 52 | "CAD", 53 | "NZD", 54 | "THB", 55 | "PLN", 56 | "AUD", 57 | "CHF", 58 | "DKK", 59 | "MXN" 60 | ] 61 | } -------------------------------------------------------------------------------- /subsystems/LSMOM/oan_config_backup.json: -------------------------------------------------------------------------------- 1 | { 2 | "fx": [ 3 | "USD_MXN", 4 | "GBP_USD", 5 | "USD_THB", 6 | "USD_ZAR", 7 | "USD_SEK", 8 | "USD_CHF", 9 | "USD_TRY", 10 | "USD_JPY", 11 | "USD_CZK", 12 | "USD_NOK", 13 | "USD_DKK", 14 | "USD_HKD", 15 | "NZD_USD", 16 | "USD_CNH", 17 | "USD_SGD", 18 | "USD_CAD", 19 | "USD_INR", 20 | "USD_HUF", 21 | "AUD_USD", 22 | "EUR_USD", 23 | "USD_PLN" 24 | ], 25 | 26 | "metals": [ 27 | "XPD_USD", 28 | "XAU_USD", 29 | "XPT_USD", 30 | "XAG_USD" 31 | ], 32 | 33 | "commodities": [ 34 | "BCO_USD", 35 | "NATGAS_USD", 36 | "XCU_USD", 37 | "WTICO_USD", 38 | "SUGAR_USD", 39 | "CORN_USD", 40 | "WHEAT_USD", 41 | "SOYBN_USD" 42 | ], 43 | 44 | "crypto": [ 45 | ], 46 | 47 | "indices": [ 48 | ], 49 | 50 | "bonds": [ 51 | "DE10YB_EUR", 52 | "USB02Y_USD", 53 | "USB05Y_USD", 54 | "USB10Y_USD", 55 | "UK10YB_GBP", 56 | "USB30Y_USD" 57 | ], 58 | 59 | "fx_codes": [ 60 | "HKD", 61 | "HUF", 62 | "GBP", 63 | "CNH", 64 | "NOK", 65 | "EUR", 66 | "TRY", 67 | "SGD", 68 | "CZK", 69 | "USD", 70 | "ZAR", 71 | "INR", 72 | "SEK", 73 | "JPY", 74 | "CAD", 75 | "NZD", 76 | "THB", 77 | "PLN", 78 | "AUD", 79 | "CHF", 80 | "DKK", 81 | "MXN" 82 | ] 83 | } -------------------------------------------------------------------------------- /subsystems/SKPRM/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/createMonster/Multi-Strategy-Quant-System/f860c5e45c26381d4d0af32e8ef5e6a22b50cfc4/subsystems/SKPRM/.DS_Store -------------------------------------------------------------------------------- /subsystems/SKPRM/oan_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "fx": [ 3 | ], 4 | 5 | "metals": [ 6 | "XPD_USD", 7 | "XAU_USD", 8 | "XPT_USD", 9 | "XAG_USD" 10 | ], 11 | 12 | "commodities": [ 13 | "BCO_USD", 14 | "NATGAS_USD", 15 | "XCU_USD", 16 | "WTICO_USD", 17 | "SUGAR_USD", 18 | "CORN_USD", 19 | "WHEAT_USD", 20 | "SOYBN_USD" 21 | ], 22 | 23 | "crypto": [ 24 | ], 25 | 26 | "indices": [ 27 | ], 28 | 29 | "bonds": [ 30 | ], 31 | 32 | "fx_codes": [ 33 | "HKD", 34 | "HUF", 35 | "GBP", 36 | "CNH", 37 | "NOK", 38 | "EUR", 39 | "TRY", 40 | "SGD", 41 | "CZK", 42 | "USD", 43 | "ZAR", 44 | "INR", 45 | "SEK", 46 | "JPY", 47 | "CAD", 48 | "NZD", 49 | "THB", 50 | "PLN", 51 | "AUD", 52 | "CHF", 53 | "DKK", 54 | "MXN" 55 | ] 56 | } -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import json 2 | import datetime 3 | import pandas as pd 4 | 5 | from dateutil.relativedelta import relativedelta 6 | 7 | import quantlib.data_utils as du 8 | import quantlib.crypto_data_utils as crypto_du 9 | import quantlib.general_utils as gu 10 | import quantlib.backtest_utils as backtest_utils 11 | import quantlib.diagnostics_utils as diagnostic_utils 12 | from quantlib.printer_utils import Printer as Printer 13 | from quantlib.printer_utils import _Colors as Colors 14 | from quantlib.printer_utils import _Highlights as Highlights 15 | 16 | from brokerage.oanda.oanda import Oanda 17 | from subsystems.LBMOM.crypto import Lbmom 18 | from subsystems.LSMOM.subsys import Lsmom 19 | from subsystems.SKPRM.subsys import Skprm 20 | 21 | import warnings 22 | warnings.filterwarnings("ignore") 23 | 24 | with open("config/auth_config.json", "r") as f: 25 | auth_config = json.load(f) 26 | 27 | with open("config/portfolio_config.json", "r") as f: 28 | portfolio_config = json.load(f) 29 | 30 | 31 | brokerage_used = portfolio_config["brokerage"] 32 | brokerage_config_path = portfolio_config["brokerage_config"][brokerage_used] 33 | db_file = portfolio_config["database"][brokerage_used] 34 | 35 | with open("config/{}".format(brokerage_config_path), "r") as f: 36 | brokerage_config = json.load(f) 37 | 38 | if brokerage_used == "oan": 39 | brokerage = Oanda(brokerage_config=brokerage_config, auth_config=auth_config) 40 | db_instruments = brokerage_config["fx"] + brokerage_config["indices"] + brokerage_config["commodities"] + brokerage_config["metals"] + brokerage_config["bonds"] + brokerage_config["crypto"] 41 | else: 42 | print("unknown brokerage, try again.") 43 | exit() 44 | 45 | 46 | 47 | subsystem = "lbmom" 48 | db_instruments = crypto_du.get_symbols() 49 | db_file = "crypto_ohlv_4h.xlsx" 50 | db_file_path = f"./Data/{db_file}" 51 | database_df = pd.read_excel(db_file_path).set_index("open_time") 52 | 53 | new_df, instruments = crypto_du.get_crypto_futures_df(interval="4h", limit=200) 54 | merge_df = pd.concat([database_df, new_df]).drop_duplicates(keep="first") 55 | 56 | 57 | #new_file = "crypto_ohlv_4h.xlsx" 58 | #new_df = pd.read_excel(new_file).set_index("open_time") 59 | #merge_df = pd.concat([new_df, database_df]).drop_duplicates() 60 | 61 | merge_df = merge_df.sort_index() 62 | merge_df.to_excel(db_file_path) 63 | historical_data = crypto_du.extend_dataframe(traded=db_instruments, df=merge_df, interval="4h") 64 | historical_data.to_excel("crypto_historical_4h.xlsx") 65 | exit() 66 | VOL_TARGET = 0.2 67 | sim_start = datetime.date.today() - relativedelta(days=30) 68 | print (sim_start) 69 | 70 | strat = Lbmom( 71 | instruments_config=portfolio_cnfig["instruments_config"][subsystem][brokerage_used], 72 | historical_df=historical_data, 73 | simulation_start=sim_start, 74 | vol_target=VOL_TARGET, 75 | brokerage_used="binance" 76 | ) 77 | portfolio_df, instruments = strat.get_subsys_pos(debug=True, use_disk=False) 78 | print (instruments) --------------------------------------------------------------------------------