Pandas:如何将一个DataFrame中的所有值除以另一个DataFrame中的值?

Pandas: how to divide all values in one DataFrame by the values in another DataFrame?

[编辑] 我真的想通了,你可以在下面看到我的回答。 ]

在您引用标题几乎相同的 之前,我已经看过它并尝试了他们的解决方案,但没有成功。我不确定我到底做错了什么,但我得到的错误与另一个问题中的不同。

我想做的是基于两个基础交易对创建一个人工交易对。这是用于配对交易。

例如。 'ETHUSD/BTCUSD'

可以在 TradingView 上看到这样的图表,我正在尝试在本地进行相同的计算。

所以,我将 ETHUSD 和 BTCUSD 的 OHLCV 数据保存在两个 DataFrame 中。我正在尝试合并它们并将每个 OHLC 值从碱基对(例如 'ETHUSD' 除以第二对,例如 'BTCUSD'

这是我到目前为止写的,它给了我一个 TypeError:

def create_synthetic_pair(base, quote, timeframe, limit):
    """
      This is not working yet. 
    """
    base_bars = exchange.fetch_ohlcv(base, timeframe, limit)
    quote_bars = exchange.fetch_ohlcv(quote, timeframe, limit)

    df_base = pd.DataFrame(base_bars[:-1], columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
    df_base['timestamp'] = pd.to_datetime(df_base['timestamp'], unit='ms')
    
    df_quote = pd.DataFrame(quote_bars[:-1], columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
    df_quote['timestamp'] = pd.to_datetime(df_quote['timestamp'], unit='ms')
    
    df_synth = (df_base.merge(df_quote, on='timestamp', how='left', suffixes=['_base', '_quote']) #how='left', sort=False)
                  .eval("""
                        open=open_base/open_quote
                        high=high_base/high_quote
                        low=low_base/low_quote
                        close=close_base/close_quote
                        """)
                )
    
    return df_synth

当我 运行 该代码时,出现以下错误:

File "/home/jonathon/Developer/*****/*****/*****/main.py", line 105, in run_bot
    create_synthetic_pair('ETH/USDT', 'BTC/USDT', "1m", 100)
  File "/home/jonathon/Developer/*****/*****/*****/main.py", line 131, in create_synthetic_pair
    .eval("""
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/frame.py", line 4234, in eval
    return _eval(expr, inplace=inplace, **kwargs)
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/computation/eval.py", line 350, in eval
    parsed_expr = Expr(expr, engine=engine, parser=parser, env=env)
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/computation/expr.py", line 811, in __init__
    self.terms = self.parse()
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/computation/expr.py", line 830, in parse
    return self._visitor.visit(self.expr)
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/computation/expr.py", line 415, in visit
    return visitor(node, **kwargs)
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/computation/expr.py", line 421, in visit_Module
    return self.visit(expr, **kwargs)
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/computation/expr.py", line 415, in visit
    return visitor(node, **kwargs)
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/computation/expr.py", line 636, in visit_Assign
    return self.visit(node.value, **kwargs)
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/computation/expr.py", line 415, in visit
    return visitor(node, **kwargs)
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/computation/expr.py", line 538, in visit_BinOp
    return self._maybe_evaluate_binop(op, op_class, left, right)
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/computation/expr.py", line 505, in _maybe_evaluate_binop
    res = op(lhs, rhs)
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/computation/expr.py", line 541, in <lambda>
    return lambda lhs, rhs: Div(lhs, rhs)
  File "/home/jonathon/.local/share/virtualenvs/*****-r-7MCNdX/lib/python3.10/site-packages/pandas/core/computation/ops.py", line 537, in __init__
    raise TypeError(
TypeError: unsupported operand type(s) for /: 'object' and 'object'

我不明白为什么当这些应该是浮点变量而不是 objects

时我会收到类型错误

我错过了什么?

所以,我实际上是自己想出来的。我会分享我的答案,以防其他人尝试做同样的事情。

实际上,TypeError 是空 DataFrame 的结果,这与 pandas 无关,而是因为我错误地调用了交换 API.

对于任何感兴趣的人,我使用的是 ccxt,并且我从这里更改了开头:

def create_synthetic_pair(base, quote, timeframe, limit):

    base_bars = exchange.fetch_ohlcv(base, timeframe, limit)
    quote_bars = exchange.fetch_ohlcv(quote, timeframe, limit)

至:

def create_synthetic_pair(base, quote, _timeframe, _limit):

    base_bars = exchange.fetch_ohlcv(base, timeframe=_timeframe, limit=_limit)
    quote_bars = exchange.fetch_ohlcv(quote, timeframe=_timeframe, limit=_limit)

修复了类型错误。但是,它仍然无法正常工作,而且奇怪的是它在除 'close' 列之外的每个列上都起作用。我最终更改了函数的这一部分:

df_synth = (df_base.merge(df_quote, on='timestamp', how='left', suffixes=['_base', '_quote']) #how='left', sort=False)
                  .eval("""
                        open=open_base/open_quote
                        high=high_base/high_quote
                        low=low_base/low_quote
                        close=close_base/close_quote
                        """)
                )

进入:

df_synth = (df_base.merge(df_quote, on='timestamp', how='left', suffixes=['_base', '_quote'], sort=False)
                  .pipe(lambda x: x.assign(open=x.open_base/x.open_quote, 
                                           high=x.high_base/x.high_quote,
                                           low=x.low_base/x.low_quote,
                                           close=x.close_base/x.close_quote,
                                           volume=x.volume_base/x.volume_quote))
                )

然后我得到了正确的 OHLCV 数据,但是有一堆来自基础和引用 DataFrames 的额外不需要的列。

为了删除这些列,我在下面添加了这个:

for name in df_synth.iteritems():
      if name[0].endswith('_base') or name[0].endswith('_quote'):
        df_synth = df_synth.drop(name[0] , 1)

现在可以使用了!

然而,我实际上仍然没有让它与 .eval() 一起工作,而是使用 .pipe(),所以如果有人想评论如何用 .eval() 做同样的事情,那么这将是受欢迎的,因为这可能是一个更优雅的解决方案。

我想我会把这个标题改成“Pandas:如何从两个基础交易对中创建一个合成交易对 OHLCV”

(如果您能想到一个不那么冗长但仍能表达该含义的标题,请告诉我)

不知道是否有人需要这个,但我想出的最终工作功能是:

def create_synthetic_pair(base_bars, quote_bars): 
    """
      This takes raw kline data from calling
      ccxt.exchange.fetch_ohlcv() as inputs,
      turns them into DataFrames, then divides 
      each base OHLCV data point value by its 
      corresponding quote value, and returns
      a new DataFrame with the new OHLCV values.
    """
    global exchange

    df_base = pd.DataFrame(base_bars[:-1], columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
    df_base['timestamp'] = pd.to_datetime(df_base['timestamp'], unit='ms')
    
    df_quote = pd.DataFrame(quote_bars[:-1], columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
    df_quote['timestamp'] = pd.to_datetime(df_quote['timestamp'], unit='ms')

    df_synth = (df_base.merge(df_quote, on='timestamp', how='left', suffixes=['_base', '_quote'], sort=False)
                  .pipe(lambda x: x.assign(open=x.open_base/x.open_quote, 
                                           high=x.high_base/x.high_quote,
                                           low=x.low_base/x.low_quote,
                                           close=x.close_base/x.close_quote,
                                           volume=x.volume_base/x.volume_quote))
                )
    for name in df_synth.iteritems():
      if name[0].endswith('_base') or name[0].endswith('_quote'):
        df_synth = df_synth.drop(name[0] , 1)

    print("\n------------------------------------------------\n"
          +f"[df_base]\n{df_base}"
          +"\n------------------------------------------------\n"
          +f"[df_quote]\n{df_quote}"
          +"\n------------------------------------------------\n"
          +f"[df_synth]\n{df_synth}"
          +"\n------------------------------------------------\n")
    return df_synth