RienNeVaPlus / wikifolio

📊 Wikifolio (unofficial) API
18 stars 6 forks source link

Buy with orderType Quote causes Missing UnderlyingQuote Error #10

Closed danielrsantana closed 2 years ago

danielrsantana commented 2 years ago

I'm using this solution to develop a nodeJS terminal app to simulate stock operations.

Everything all right when buying with limit as orderType but something goes wrong when using quote instead. Am I missing some parameter?

Expected Behavior

When calling the buy method with quote as typeOrder the operation should work just like 'limit' orders.

Current Behavior

The following error appears:

# Unknown Error: Unable to submit order (Bei Requoteorders muss das UnderlyingQuote angegeben werden.)

Steps to Reproduce

1) NodeJS, Yarn and Typescript

2) Code to buy stocks (simplified to make it easier to find the possible cause)

wikifolio.services.ts

import Api, { OrderParam } from 'wikifolio';

const API_KEY = 'HIDDEN DUE SECURITY REASONS';
const SAMPLE_ISIN = 'DE000LS9NMQ9';

const getExpirationDate = (): Date => {
  const now = new Date();
  now.setMinutes(now.getMinutes() + 30);
  return new Date(now);
};

export const buyWikifolio = async (
  email: string,
  password: string,
  order: Partial<OrderParam>
) => {
  const api = new Api({ email, password });
  const wikifolio = api.wikifolio(API_KEY);

  // with **_quote_** the error (Bei Requoteorders muss das UnderlyingQuote angegeben werden) occurs
  const orderType:any = 'limit';

  order = {
    ...order,
    orderType,
    expiresAt: getExpirationDate()
  };

  console.log('this is my order', order);

  return await wikifolio.buy(order);
};

index.ts

import { buyWikifolio } from './services/wikifolio.services';
import { Order, OrderParam } from 'wikifolio';

const order: Partial<OrderParam> = {
  amount: 2,
  limitPrice: 100,
  underlyingIsin: 'DE000LS9NMQ9',
};

buyWikifolio(email, password, order)
  .then((result: Order) => {
    console.log(result);
  })
  .catch((error) => console.log(error))
  .finally(() => process.exit());

package.json

  "dependencies": {
    "request": "^2.88.2",
    "wikifolio": "^0.3.3"
  },
  "devDependencies": {
    "typescript": "^4.4.3"
  }

tsconfig.json

{
  "compilerOptions": {
    "esModuleInterop": true,
    "module": "CommonJS",
    "noImplicitAny": true,
    "outDir": "build",
    "preserveConstEnums": true,
    "removeComments": true,
    "sourceMap": false
  },
  "include": ["src/**/*", "services", "index.ts"],
  "exclude": ["node_modules", "**/*.spec.ts"]
}

Context (Environment)

Trying to execute a quote operation. In the following screenshot I have two examples of the response the API call is giving me.

In the first attempt I tried to send all the possible values and in the second one only the limitPrice, amount, underlyingIsin, orderType and expiresAt.

image

Thanks in advance

jekru commented 2 years ago

POST https://www.wikifolio.com/api/virtualorder/placeorder has such a payload:

{
  "wikifolioId":"3f7f7343-a0a5-42ed-b038-839b63498c10",
  "underlyingIsin":"US0378331005",
  "amount":1,
  "buysell":"buy",
  "orderType":"quote",
  "limitPrice":null,
  "stopPrice":null,
  "takeProfitLimitPrice":null,
  "stopLossStopPrice":null,
  "stopLossLimitPrice":null,
  "validUntil":null,
  "quoteId":"42b12a32-4df0-4e58-92ae-81addbd7dc59"
}

We are not sending quoteId with the api request. That should be the problem. But where can we get this parameter? Let's click on "Preis holen" an see what happens.

example_wikifolio

No new request is made, so there has to be some kind of conection already established because the parameter orderId is not static. Websockets? Yeah!

wss://www.wikifolio.com/de/de/signalr/connect?transport=webSockets&clientProtocol=[clientProtocol]&connectionToken=[connectionToken]&connectionData=[{"name":"livehub"},{"name":"quotehub"}]&tid=[tid]

The websocket message that is being sent looks like this:

{
    "A": [
        "ea8e9c3f-fb36-4a89-8cf9-f1bc3a116868",
        "US0378331005",
        "1",
        910
    ],
    "H": "quotehub",
    "I": 25,
    "M": "GetQuote",
}

A[0]: string := GUID (but not the orderId!) A[1]: string := ISIN A[2]: number := AMOUNT A[3]: number := 910 (BUY) | 920 (SELL) "I": number := INCREMENTING ID (since the connection was established)

The websocket response looks like this:

[
    {
        "H": "QuoteHub",
        "M": "quoteCallback",
        "A": [
            {
                "QuoteId": "f5fb9ff0-14d9-4c1f-ad38-c88f8c9c949c",
                "WaitForManuelResponse": false,
                "Ask": 122.41,
                "Bid": 122.2,
                "ValidityDuration": 3000,
                "Currency": "EUR"
            }
        ]
    }
]

We finally got the parameter "QuoteId" that we have to add to our json payload with the post request. That was the debugging/reverse engineering part, now the implementing part begins.

RienNeVaPlus commented 2 years ago

Implemented by jekru in v0.3.4