套利是利用货币兑换价值差异赚取利润的过程
考虑一个以一定数量的货币X开头的人,经历一系列交易,最后得到更多的X(比他最初的那样)。
给定n种货币和汇率表(nxn),设计一个人应该用来获得最大利润的算法,假设他没有多次执行一次交易。
我想到了这样的解决方案:
w(curr,source)
(边缘到源的权重)。 虽然这看起来不错,但我仍然怀疑这个算法的正确性和问题的完整性。(问题是NP-Complete?)因为它有点类似于旅行商问题。
为此问题寻找您的意见和更好的解决方案(如果有的话)。
感谢。
修改:
谷歌搜索这个主题带我去了here,其中已经解决了套利检测问题,但是最大套利交换没有。这可能会作为参考。
答案 0 :(得分:29)
Dijkstra's不能在这里使用,因为没有办法修改Dijkstra's以返回最长路径,而不是最短路径。一般来说,longest path problem实际上是您所怀疑的NP-complete,并且与您建议的旅行商问题有关。
您正在寻找的(如您所知)是一个边缘权重大于1的循环,即w 1 * w 2 * w 3 * ...> 1.如果我们记录双方的日志,我们可以重新设想这个问题,将其改为总和而不是产品:
log(w 1 * w 2 * w 3 ...)>日志(1)
=> log(w 1 )+ log(w 2 )+ log(w 3 )...> 0
如果我们采取负面日志......
=> -log(w 1 ) - log(w 2 ) - log(w 3 )...< 0(注意不等式翻转)
所以我们现在只是在图中寻找负循环,可以使用Bellman-Ford算法解决(或者,如果你不需要知道路径,Floyd-Warshall算法)
首先,我们转换图表:
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
w[i][j] = -log(w[i][j]);
然后我们执行标准的Bellman-Ford
double dis[N], pre[N];
for (int i = 0; i < N; ++i)
dis[i] = INF, pre[i] = -1;
dis[source] = 0;
for (int k = 0; k < N; ++k)
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
if (dis[i] + w[i][j] < dis[j])
dis[j] = dis[i] + w[i][j], pre[j] = i;
现在我们检查负循环:
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
if (dis[i] + w[i][j] < dis[j])
// Node j is part of a negative cycle
然后,您可以使用pre
数组来查找负循环。从pre[source]
开始,然后继续前进。
答案 1 :(得分:6)
当只有大约150 currencies currently in existence时,这是一个NP难问题的事实并不重要,我怀疑你的外汇经纪人最多只能让你交易20对。因此,我的n
种货币算法是:
n
和分支因子n
的树。树的节点是货币,树的根是您的起始货币X
。两个节点(货币)之间的每个链接都具有权重w
,其中w
是两种货币之间的外汇汇率。X
)与此节点的货币之间的汇率。X
的所有节点(也许您应该保留指向这些节点的指针列表以加速算法的这个阶段)。只有n^n
这些(在大O符号方面非常低效,但请记住,您的n
约为20)。具有最高累积外汇汇率的汇率是您的最佳汇率和(如果是正值)这些节点之间通过树的路径表示以货币X
开头和结尾的套利周期。O(n^n)
降低到O(n)
:
X
的节点,请不要生成任何子节点。n
减少到1,每个节点都会生成所有n
个子节点,并且只添加具有最大累积外汇汇率的子节点(当转换回货币{{1 }})。 答案 2 :(得分:4)
我们可以perform gaussian elimination并检查我们是否只获得1个线性独立的行。如果没有,额外的线性独立行将提供有关套利可用货币对数量的信息。
答案 3 :(得分:1)
记录转换率。然后,您试图找到从X开始的循环,其中具有正,负或零加权边的图中的最大和。这是一个NP难问题,因为在未加权图中找到最大周期的简单问题是NP难。
答案 4 :(得分:0)
除非我完全搞砸了,否则我相信我的实现可以使用Bellman-Ford算法:
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
std::vector<std::vector<double>> transform_matrix(std::vector<std::vector<double>>& matrix)
{
int n = matrix.size();
int m = matrix[0].size();
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
{
matrix[i][j] = log(matrix[i][j]);
}
}
return matrix;
}
bool is_arbitrage(std::vector<std::vector<double>>& currencies)
{
std::vector<std::vector<double>> tm = transform_matrix(currencies);
// Bellman-ford algorithm
int src = 0;
int n = tm.size();
std::vector<double> min_dist(n, INFINITY);
min_dist[src] = 0.0;
for (int i = 0; i < n - 1; ++i)
{
for (int j = 0; j < n; ++j)
{
for (int k = 0; k < n; ++k)
{
if (min_dist[k] > min_dist[j] + tm[j][k])
min_dist[k] = min_dist[j] + tm[j][k];
}
}
}
for (int j = 0; j < n; ++j)
{
for (int k = 0; k < n; ++k)
{
if (min_dist[k] > min_dist[j] + tm[j][k])
return true;
}
}
return false;
}
int main()
{
std::vector<std::vector<double>> currencies = { {1, 1.30, 1.6}, {.68, 1, 1.1}, {.6, .9, 1} };
if (is_arbitrage(currencies))
std::cout << "There exists an arbitrage!" << "\n";
else
std::cout << "There does not exist an arbitrage!" << "\n";
std::cin.get();
}