我想出了一种算法来查找pairs
的三元组(我称它们为trairs
),条件是所有元素中必须全部存在3个元素(硬币),而只有3个元素3 pairs
。
但是,可能有可能以更优雅的方式解决相同的问题。例如,我正在索引所有循环,这使它看起来特别复杂。另外,那里的break
令我不舒服!
输入数据为pairs
,它是list
中的str
:
例如。 pairs = ['BCH/BTC','BCH/ETH','DASH/USD','BTC/USDT','ETH/BTC']
所需的输出是list
个字符串中的一个list
:
例如。 trair = [['BCH/BTC','BCH/ETH','ETH/BTC]]
def find_trairs(exchange):
''' Find possible triplets of pairs (trairs) that can be traded for unbalance.
Example of trairs:
'ETC/BTC' 'ETC/ETH' 'ETH/BTC'
'BCH/BTC' 'BCH/EUR' 'BTC/EUR'
'''
exchange_pairs = exchange.symbols #loads all pairs from the exchange.
pairs = list(filter(lambda x: not '.d' in x, exchange_pairs)) #filters off
#the darkpool pairs.
pair = ['', '', '']
coin = ['', '', '']
trair = []
#Semi-optimized loop to look for triplece of pairs.
#Example:['BCH/BTC', 'BCH/EUR', 'BTC/EUR']
for i in range(len(pairs)-3):
#not all coins are 3 digits long, we must find the slash that separetes
#each coin in order to have a robust algorithm.
slash_position = pairs[i].find('/')
coin[0] = pairs[i][0:slash_position]
coin[1] = pairs[i][slash_position+1:]
for j in range(i+1, len(pairs)-2):
if (coin[0] in pairs[j]):
slash_position = pairs[j].find('/')
coin[2] = pairs[j][slash_position+1:]
for k in range(j+1, len(pairs)-1):
if coin[1] in pairs[k] and coin[2] in pairs[k]:
trair.append([pairs[i], pairs[j], pairs[k]])
break
return trair
有任何提示或评论吗?
答案 0 :(得分:3)
使用itertools排列,并过滤结果并消除重复项:
import itertools
currency_pairs = ['BCH/BTC', 'BCH/ETH', 'DASH/USD', 'BTC/USDT', 'ETH/BTC']
set_triplets = set()
for triplet in itertools.permutations(currency_pairs, 3):
c1, c2 = triplet[0].split('/')
if (c1 in triplet[1] or c1 in triplet[2]) and (c2 in triplet[1] or c2 in triplet[2]):
set_triplets.add(tuple(sorted(triplet)))
for triplet in set_triplets:
print(triplet)
('BCH/ETH', 'BTC/USDT', 'ETH/BTC')
('BCH/BTC', 'BCH/ETH', 'BTC/USDT')
('BCH/BTC', 'BCH/ETH', 'ETH/BTC')
请注意,三元组中的货币对的顺序在字典上是递增的,不要期望第一个货币对始终是两个货币对之间的链接。
答案 1 :(得分:3)
您可以使用
coins = set('/'.join(pairs).split('/'))
在交易所获得一组所有可能的硬币。然后,您可以使用itertools.combinations
和
triples = combinations(coins, 3)
通过取三元组中len 2的组合,可以得到“ trairs”。
trairs = [{frozenset(pair) for pair in combinations(triple, 2)}
for triple in triples]
结果是3个项目集的列表,其中每个项目都是代表硬币对的冻结集。
交易所可能不直接支持所有可能的货币对。如果是这样,您可以添加一个额外的过滤步骤以删除无效的“ trairs”。
pairset = set(frozenset(pair.split('/')) for pair in pairs)
trairs = [trair for trair in trairs if trair <= pairset]
<=
检查trair是否是配对对的子集。
frozenset的集合列表与问题的结构更匹配,因此可以满足您的需求,但这并不完全是指定的输出形式。
您可以使用
将冻结的集转换回字符串,将三元组转换为列表。[['/'.join(pair) for pair in trair] for trair in trairs]]
组合实际上是无序的,但是尚不明确这个问题是否重要,因为购买例如BTC/ETH
与销售ETH/BTC
等相同,目前尚不清楚相同三元组的其他订购有什么用途。因此,您可以将三元组保留为一组,并使用像这样的字母对。
[{'/'.join(sorted(pair)) for pair in trair} for trair in trairs]]
答案 2 :(得分:2)
这里是主要使用标准库功能的方法:
id organization invoice salesOrderNumber
12830 43 12975 705
12831 43 12976 705
会给:
[([['BCH','BTC'],['BCH','ETH'],['ETH','BTC'])]
答案 3 :(得分:2)
有效方法
这将很快在输入列表中搜索有效的三元组。希望它也相当清楚和简单。但这确实规范了对的顺序(即,将每个对按字母顺序排列)。让我知道是否有问题。
pairs = ['BCH/BTC','BCH/ETH','DASH/USD','BTC/USDT','ETH/BTC']
# make a dict of all alphabetically higher partners for each symbol
pair_dict = {}
for pair_str in pairs:
p0, p1 = sorted(pair_str.split('/'))
# create sets if needed, then record this pair
pair_dict.setdefault(p0, set())
pair_dict.setdefault(p1, set())
pair_dict[p0].add(p1)
# process the dict, finding all valid triplets of pairs
triplets = list()
for p0 in pair_dict:
p0_pairs = pair_dict[p0]
for p1 in p0_pairs:
p1_pairs = pair_dict[p1]
for p2 in p1_pairs:
if p2 in p0_pairs:
# there's a chain from p0 to p1 to p2 to p0;
# add them to the list of triplets
triplets.append((p0, p1, p2))
final = [[p0+'/'+p1, p1+'/'+p2, p2+'/'+p0] for p0, p1, p2 in triplets]
print(final)
# [['BCH/BTC', 'BTC/ETH', 'ETH/BCH']]
我使用集而不是pair_dict
中的列表,因为它们可以更快地搜索并且可以消除任何重复项。另外,for p0 in pair_dict
与for p0 in pair_dict.keys()
相同,而for p0, p1, p2 in triplets
的意思是“从triplets
中取出每个元素并将其拆分为p0
,p1
和p1
变量。”
更简单的方法
如果您正在寻找更简单的方法(尽管效率较低),则可以尝试以下代码。
请注意,这依赖于一些有趣的事情。 1.如果您对每对中的硬币进行排序,并且对每个三元组中的硬币对进行排序,那么可以确保每个有效的三元组看起来像['a / b','a / c','b / c'],其中a,b和c是不同的硬币,按字母顺序排列。 2.如果您向itertools.combinations()
提供排序列表,则三元组将产生will also be sorted。
因此,下面的代码在每个对中进行排序,然后对对列表进行排序,然后使用itertools.combinations()
来获取已排序的三元组。然后,它检查这些三胞胎中的任何一个是否与所需的模式匹配。
import itertools
# added another pair to make it more interesting
pairs = ['BCH/BTC','BCH/ETH','DASH/USD','BTC/USDT','ETH/BTC','USDT/ETH']
pairs_normalized = sorted(sorted(pair.split('/')) for pair in pairs)
triplets = [
(p1, p2, p3)
for p1, p2, p3 in itertools.combinations(pairs_normalized, 3)
# look for ['a/b', 'a/c', 'b/c'] pattern
if p1[0] == p2[0] and p1[1] == p3[0] and p2[1] == p3[1]
]
output = [['/'.join(p) for p in triplet] for triplet in triplets]
print(output)
# [['BCH/BTC', 'BCH/ETH', 'BTC/ETH'], ['BTC/ETH', 'BTC/USDT', 'ETH/USDT']]
答案 4 :(得分:2)
列出理解力,我敢肯定,这可以改善,您可以尝试这样的事情:
>>> pairs = ['BCH/BTC','BCH/ETH','DASH/USD','BTC/USDT','ETH/BTC']
# ['BCH/BTC','BCH/ETH','DASH/USD','BTC/USDT','ETH/BTC']
获取硬币:
>>> coins = [j for i in pairs for j in i.split('/')]
# ['BCH', 'BTC', 'BCH', 'ETH', 'DASH', 'USD', 'BTC', 'USDT', 'ETH', 'BTC']
获取出现多次的硬币并保存在集合中,以避免重复
>>> coins = {coin for coin in coins if coins.count(coin)>1}
# {'BCH', 'BTC', 'ETH'}
找到只有这些硬币出现的地方:
>>> trairs = [i for i in pairs for j in coins if i.split('/')[0] and i.split('/')[1] in j]
# ['BCH/BTC', 'BCH/ETH', 'ETH/BTC']
使用过滤器:
>>> trairs = filter(lambda x: (x.split('/')[0] and x.split('/')[1]) in coins, pairs)
# ['BCH/BTC', 'BCH/ETH', 'ETH/BTC']
itertools的新更新:
>>> coins = {j for j in set('/'.join(pairs).split('/')) if '/'.join(pairs).split('/').count(j)>1}
# {'BCH', 'BTC', 'ETH'}
然后
>>> trairs = list(itertools.combinations(coins, 2))
# [('ETH', 'BCH'), ('ETH', 'BTC'), ('BCH', 'BTC')]
答案 5 :(得分:0)
谢谢大家的帮助。
当前实现为:
import ccxt
from collections import Counter
from itertools import combinations, chain
def parse_pair(raw_pair):
return raw_pair.split('/')
def is_trair(trair_candidate):
# assuming that all currencies appear twice means we have a trair
currency_counts = Counter(chain.from_iterable(trair_candidate))
return set(currency_counts.values()) == {2}
def format_trairs(u_trair):
'''fortmat the trairs to the correct format. List of List of str.
input:
u_trair: trairs in the format List of Tuples of list of strings.
eg.:[(['ABT','BTC'],['ABT',ETH'],['ETH','BTC])]
output:
trair: trais in the format List of list of str.
['ABT/BTC', 'ABT/ETH', 'ETH/BTC']
'''
trair= [] #stores the trairs in the correct format.
for one_trair in u_trair:
t_trair = [] #temporary trair.
for one_pair in one_trair:
t_trair.append(one_pair[0]+'/'+one_pair[1])
trair.append(t_trair)
return trair
exchange = ccxt.kucoin()
market = exchange.load_markets()
exchange_pairs = exchange.symbols
raw_pairs = list(filter(lambda x: not '.d' in x, exchange_pairs))
pairs = map(parse_pair, raw_pairs)
trair_candidates = combinations(pairs, r=3)
#filter the actual trairs from all trair_candidates
u_trair = list(filter(is_trair,trair_candidates)) #unformated trairs.
trair = format_trairs(u_trair) #formats the trairs to list of list os strings.