Origin
Stocks and Digital Currency
The digital currency market is a 7*25, 365 days a year, non-stop trading market that generates huge amounts of data every day. Compared to the A-share market, which trades for only 4 hours a day, it is very difficult to get milliseconds of data. The digital currency market is undoubtedly a more friendly market.
I even had a fight with my hairdresser yesterday, he still insists that quantization is evil and is stealing money from them. And my point is Quantization is the big trend, and those who know quantization are facing traditional traders who don’t understand quantization in a downward spiral. The only way is to embrace quantization as soon as possible, but people have their own aspirations and cannot be persuaded.
The digital currency market is constantly evolving, from a person can make a lot of money by manually moving, to manual moving can not be profitable to move to the program to move arbitrage, then the program with the program coupled with a simple indicator for programmed trading, and then, the simple indicator began to fail, the cost of gradually began to introduce the concept of factors. Higher level began to high frequency.
This step by step can be clearly seen. The digital currency market is a gradual conversion from the cognitive threshold to the technical threshold of the process, at the beginning as long as you have the determination to gamble, you can obtain profiteering, to the present you can only clear away the fog in front of you, cross the threshold of cognition, and at the same time technically sound in order to obtain enough to satisfy their own profits.
All of this is similar to the early days of the reopening, except that this is a 5 times the speed of the market, everything is in the rapid evolution. I hope that students reading this article can embrace the oncoming wave together. Get your own share of the glory.
Multifactor and Digital Currency
Back to multi-factor, this article does not involve complex mathematical modeling and logical derivation, is simple to use the digital currency spot market as a data source to build a factor back test framework, to facilitate the evaluation of factors.
Factor can be regarded as an indicator, can also be written as an expression, which represents a kind of investment logic, reflects a kind of return information.
For example: The closing price factor assumes that the stock price predicts future returns, and that higher stock prices predict higher (or lower) returns. Constructing a portfolio of this factor is equivalent to a strategy of buying high priced stocks on a regular rotation. Factors that consistently generate excess returns are often referred to as alpha, such as the market capitalization factor and the momentum factor, which are proven effective factors.
Both the stock market and the digital currency market are extremely complex and it is impossible to fully predict future returns, but there is some predictability. Effective Alpha investment models gradually expire as more capital is invested, but new models and new Alpha will be created.
Market capitalization factor was very successful in the A-share market, since 2007, a decade of backtesting, simply buy the lowest market capitalization stocks, adjusted every day, gained more than 400 times the return, far more than the broader market. But in 2017, the small-cap factor failed, and the value factor became popular, reflecting the limitations of a single factor. We need to weigh the validation and use of factors. Finding factors is the basis of the strategy, combining multiple uncorrelated valid factors can build a better strategy.
Code implementation
Introducing related libraries
1 | # Introduction of related libraries |
Build data environment
The source of the data is the binance exchange spot market, because all these data have been deposited into the database, so that it is convenient for local backtesting and research, I have selected the species with a relatively large trading volume, and opened the trading pairs in the USDT perpetual futures at the same time. As I said before, multi-factor is actually a strategy for selecting coins, which requires that the coins should be sufficiently large, so as to have enough space to select.
First build a database environment to facilitate the data call
1 | ## Defining database-related constants |
Define commonly used functions
Then define a few commonly used functions to make it easier to call them.
1 | #———————————————————— Defining Related Functions ————————————————————# |
Print database information
Let’s print out the tables that are in the database memory
1 | ## Get the table names of all tables in the specified database |
output:
1 | ['1inch_usdt', 'aave_usdt', 'aca_usdt', 'ach_usdt', 'acm_usdt', 'ada_usdt', 'adx_usdt', 'agld_usdt', 'aion_usdt', 'akro_usdt', 'alcx_usdt', 'algo_usdt', 'alice_usdt', 'alpaca_usdt', 'alpha_usdt', 'alpine_usdt', 'amp_usdt', 'anc_usdt', 'ankr_usdt', 'ant_usdt', 'any_usdt', 'ape_usdt', 'api3_usdt', 'apt_usdt', 'ar_usdt', 'ardr_usdt', 'arpa_usdt', 'asr_usdt', 'astr_usdt', 'ata_usdt', 'atm_usdt', 'atom_usdt', 'auction_usdt', 'aud_usdt', 'audio_usdt', 'auto_usdt', 'ava_usdt', 'avax_usdt', 'axs_usdt', 'badger_usdt', 'bake_usdt', 'bal_usdt', 'band_usdt', 'bar_usdt', 'bat_usdt', 'bcc_usdt', 'bch_usdt', 'bchabc_usdt', 'bchsv_usdt', 'beam_usdt', 'bel_usdt', 'beta_usdt', 'bico_usdt', 'bifi_usdt', 'bkrw_usdt', 'blz_usdt', 'bnb_usdt', 'bnt_usdt', 'bnx_usdt', 'bond_usdt', 'bsw_usdt', 'btc_usdt', 'btcst_usdt', 'btg_usdt', 'bts_usdt', 'btt_usdt', 'bttc_usdt', 'burger_usdt', 'busd_usdt', 'bzrx_usdt', 'c98_usdt', 'cake_usdt', 'celo_usdt', 'celr_usdt', 'cfx_usdt', 'chess_usdt', 'chr_usdt', 'chz_usdt', 'city_usdt', 'ckb_usdt', 'clv_usdt', 'cocos_usdt', 'comp_usdt', 'cos_usdt', 'coti_usdt', 'crv_usdt', 'ctk_usdt', 'ctsi_usdt', 'ctxc_usdt', 'cvc_usdt', 'cvp_usdt', 'cvx_usdt', 'dai_usdt', 'dar_usdt', 'dash_usdt', 'data_usdt', 'dcr_usdt', 'dego_usdt', 'dent_usdt', 'dexe_usdt', 'df_usdt', 'dgb_usdt', 'dia_usdt', 'dnt_usdt', 'dock_usdt', 'dodo_usdt', 'doge_usdt', 'dot_usdt', 'drep_usdt', 'dusk_usdt', 'dydx_usdt', 'egld_usdt', 'elf_usdt', 'enj_usdt', 'ens_usdt', 'eos_usdt', 'eps_usdt', 'epx_usdt', 'erd_usdt', 'ern_usdt', 'etc_usdt', 'eth_usdt', 'eur_usdt', 'farm_usdt', 'fet_usdt', 'fida_usdt', 'fil_usdt', 'fio_usdt', 'firo_usdt', 'fis_usdt', 'flm_usdt', 'flow_usdt', 'flux_usdt', 'for_usdt', 'forth_usdt', 'front_usdt', 'ftm_usdt', 'ftt_usdt', 'fun_usdt', 'fxs_usdt', 'gal_usdt', 'gala_usdt', 'gbp_usdt', 'ghst_usdt', 'glmr_usdt', 'gmt_usdt', 'gmx_usdt', 'gno_usdt', 'grt_usdt', 'gtc_usdt', 'gto_usdt', 'gxs_usdt', 'hard_usdt', 'hbar_usdt', 'hc_usdt', 'hft_usdt', 'hifi_usdt', 'high_usdt', 'hive_usdt', 'hnt_usdt', 'hot_usdt', 'icp_usdt', 'icx_usdt', 'idex_usdt', 'ilv_usdt', 'imx_usdt', 'inj_usdt', 'iost_usdt', 'iota_usdt', 'iotx_usdt', 'iris_usdt', 'jasmy_usdt', 'joe_usdt', 'jst_usdt', 'juv_usdt', 'kava_usdt', 'kda_usdt', 'keep_usdt', 'key_usdt', 'klay_usdt', 'kmd_usdt', 'knc_usdt', 'kp3r_usdt', 'ksm_usdt', 'lazio_usdt', 'ldo_usdt', 'lend_usdt', 'lever_usdt', 'lina_usdt', 'link_usdt', 'lit_usdt', 'loka_usdt', 'lqty_usdt', 'lrc_usdt', 'lsk_usdt', 'ltc_usdt', 'lto_usdt', 'luna_usdt', 'magic_usdt', 'mana_usdt', 'mask_usdt', 'matic_usdt', 'mbl_usdt', 'mbox_usdt', 'mc_usdt', 'mco_usdt', 'mdt_usdt', 'mdx_usdt', 'mft_usdt', 'mina_usdt', 'mir_usdt', 'mith_usdt', 'mkr_usdt', 'mln_usdt', 'mob_usdt', 'movr_usdt', 'mtl_usdt', 'multi_usdt', 'nano_usdt', 'nbs_usdt', 'nbt_usdt', 'near_usdt', 'neo_usdt', 'nexo_usdt', 'nkn_usdt', 'nmr_usdt', 'npxs_usdt', 'nu_usdt', 'nuls_usdt', 'ocean_usdt', 'og_usdt', 'ogn_usdt', 'om_usdt', 'omg_usdt', 'one_usdt', 'ong_usdt', 'ont_usdt', 'ooki_usdt', 'op_usdt', 'orn_usdt', 'oxt_usdt', 'pax_usdt', 'paxg_usdt', 'people_usdt', 'perl_usdt', 'perp_usdt', 'pha_usdt', 'pla_usdt', 'pnt_usdt', 'pols_usdt', 'poly_usdt', 'polyx_usdt', 'pond_usdt', 'porto_usdt', 'powr_usdt', 'psg_usdt', 'pundix_usdt', 'pyr_usdt', 'qi_usdt', 'qnt_usdt', 'qtum_usdt', 'quick_usdt', 'rad_usdt', 'ramp_usdt', 'rare_usdt', 'ray_usdt', 'reef_usdt', 'rei_usdt', 'rep_usdt', 'req_usdt', 'rgt_usdt', 'rif_usdt', 'rlc_usdt', 'rndr_usdt', 'rose_usdt', 'rpl_usdt', 'rsr_usdt', 'rune_usdt', 'sand_usdt', 'santos_usdt', 'sc_usdt', 'scrt_usdt', 'sfp_usdt', 'shib_usdt', 'skl_usdt', 'slp_usdt', 'snx_usdt', 'sol_usdt', 'spell_usdt', 'srm_usdt', 'steem_usdt', 'stg_usdt', 'stmx_usdt', 'storj_usdt', 'storm_usdt', 'stpt_usdt', 'strat_usdt', 'strax_usdt', 'stx_usdt', 'sun_usdt', 'susd_usdt', 'sushi_usdt', 'sxp_usdt', 'sys_usdt', 't_usdt', 'tct_usdt', 'tfuel_usdt', 'theta_usdt', 'tko_usdt', 'tlm_usdt', 'tomo_usdt', 'torn_usdt', 'trb_usdt', 'tribe_usdt', 'troy_usdt', 'tru_usdt', 'trx_usdt', 'tusd_usdt', 'tvk_usdt', 'twt_usdt', 'uma_usdt', 'unfi_usdt', 'uni_usdt', 'usdc_usdt', 'usdp_usdt', 'ust_usdt', 'utk_usdt', 'ven_usdt', 'vet_usdt', 'vgx_usdt', 'vidt_usdt', 'vite_usdt', 'voxel_usdt', 'vtho_usdt', 'wan_usdt', 'waves_usdt', 'waxp_usdt', 'win_usdt', 'wing_usdt', 'wnxm_usdt', 'woo_usdt', 'wrx_usdt', 'wtc_usdt', 'xec_usdt', 'xem_usdt', 'xlm_usdt', 'xmr_usdt', 'xno_usdt', 'xrp_usdt', 'xtz_usdt', 'xvg_usdt', 'xvs_usdt', 'xzc_usdt', 'yfi_usdt', 'yfii_usdt', 'ygg_usdt', 'zec_usdt', 'zen_usdt', 'zil_usdt', 'zrx_usdt'] 360 |
Then output the data in the table to see the data structure :
1 | symbol = 'btc_usdt' |
output:
id | open_time_GMT8 | open | high | low | close | volume | amount | |
---|---|---|---|---|---|---|---|---|
0 | 2291854 | 2022-01-01 00:00:00 | 48005.37 | 48027.31 | 47937.50 | 48004.75 | 50.29149 | 2.413640e+06 |
1 | 2291855 | 2022-01-01 00:01:00 | 48007.21 | 48011.78 | 47951.50 | 47951.50 | 14.75541 | 7.080488e+05 |
2 | 2291856 | 2022-01-01 00:02:00 | 47956.29 | 47992.36 | 47944.49 | 47965.46 | 15.33062 | 7.353789e+05 |
3 | 2291857 | 2022-01-01 00:03:00 | 47965.46 | 47970.25 | 47910.56 | 47954.34 | 13.35734 | 6.403608e+05 |
4 | 2291858 | 2022-01-01 00:04:00 | 47954.35 | 47971.49 | 47949.55 | 47955.58 | 8.34380 | 4.001467e+05 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
349916 | 2641770 | 2022-08-31 23:56:00 | 20148.68 | 20155.55 | 20143.12 | 20151.50 | 170.79243 | 3.441419e+06 |
349917 | 2641771 | 2022-08-31 23:57:00 | 20152.62 | 20153.10 | 20130.85 | 20142.19 | 227.70751 | 4.586203e+06 |
349918 | 2641772 | 2022-08-31 23:58:00 | 20143.65 | 20151.31 | 20136.47 | 20145.66 | 160.46265 | 3.232340e+06 |
349919 | 2641773 | 2022-08-31 23:59:00 | 20144.40 | 20158.24 | 20138.16 | 20140.63 | 193.27150 | 3.894068e+06 |
349920 | 2641774 | 2022-09-01 00:00:00 | 20142.26 | 20166.17 | 20131.97 | 20158.42 | 294.71744 | 5.938896e+06 |
349921 rows × 8 columns
1 | # Filter the tables to keep only the ones with high recognition. |
output: 135
1 | ## All the data is stored in a file for subsequent analysis. |
Grouping of data
1 | df_close = pd.DataFrame(index=pd.date_range(start=start_time, end=end_time, freq=rule_type),columns=df_dict.keys()) |
1 | # Normalization process and output |
As we can see the market is very poor going from 1.0 at the beginning of the year to 0.3 in September and the market capitalization is down 35% of what it started with
The backtesting engine
1 | # Backtesting engine |
1 | #Volume |
1 | #3 hour momentum factor |
1 | #24 hour momentum factor |
1 | #Volume Factor |
1 | # Volatility factor |
1 | # Volume and closing price correlation factors |
1 | # Normalization function, removing missing and extreme values and normalized |
polyfactor synthesis
1 | ## Multi-factor backtesting |
Summary
This paper is a replication of the inventor’s article, with only a few parameter changes, so the results are similar.
In the backtesting data, we can see that the multi-factor performance is not as good as the single-factor performance of Momentum, and we are looking for multi-factors with better performance. We are looking for better multi-factor performance. There are still a lot of ways to play with multi-factor strategies and a lot of room for improvement, so I hope we can discuss this together.