From af5d45d37f5aa9494503b58eb7fc263be322f7f9 Mon Sep 17 00:00:00 2001 From: Paul Squires Date: Fri, 18 Aug 2023 12:25:34 -0230 Subject: [PATCH] Major changes to Order Entry, Option/Futures Assignment, Reconciliation, and GUI elements. May possibly affect quantiry values of some transactions already entered in your database. --- IB-Tracker/src/ActiveTrades/ActiveTrades.cpp | 57 +++++++++++++------ IB-Tracker/src/Config/Config.cpp | 16 +++++- IB-Tracker/src/Config/Config.h | 3 +- .../src/CustomTextBox/CustomTextBox.cpp | 1 + IB-Tracker/src/Database/database.cpp | 2 +- IB-Tracker/src/Database/trade.cpp | 4 +- IB-Tracker/src/Database/trade.h | 7 ++- IB-Tracker/src/MainWindow/MainWindow.cpp | 15 ----- IB-Tracker/src/MainWindow/tws-client.cpp | 9 +-- IB-Tracker/src/Reconcile/Reconcile.cpp | 6 +- IB-Tracker/src/TradeDialog/TradeDialog.cpp | 8 +-- IB-Tracker/src/TradeDialog/TradeDialog.h | 31 ++++++---- .../src/TradeDialog/TradeDialogControls.cpp | 40 +++++++++---- .../src/TradeDialog/TradeDialogSave.cpp | 16 ++++-- IB-Tracker/src/TradeGrid/TradeGrid.cpp | 22 +------ IB-Tracker/src/TradeHistory/TradeHistory.cpp | 40 ++++++++----- IB-Tracker/src/TradeHistory/TradeHistory.h | 2 +- IB-Tracker/src/Utilities/ListBoxData.cpp | 36 +++++++----- IB-Tracker/src/Utilities/UserMessages.h | 3 +- README.md | 2 +- 20 files changed, 191 insertions(+), 129 deletions(-) diff --git a/IB-Tracker/src/ActiveTrades/ActiveTrades.cpp b/IB-Tracker/src/ActiveTrades/ActiveTrades.cpp index 3aa8e8f8..6e5da750 100644 --- a/IB-Tracker/src/ActiveTrades/ActiveTrades.cpp +++ b/IB-Tracker/src/ActiveTrades/ActiveTrades.cpp @@ -157,18 +157,18 @@ void ActiveTrades_ShowActiveTrades() // Create the new ListBox line data and initiate the new market data. int categoryHeader = -1; - for (const auto& trade : trades) { + for (auto& trade : trades) { // We are displaying only open trades if (trade->isOpen) { + // Set the decimals for this tickerSymbol. Most will be 2 but futures can have a lot more. + trade->tickerDecimals = GetTickerDecimals(trade->tickerSymbol); + if (trade->category != categoryHeader) { ListBoxData_AddCategoryHeader(hListBox, trade); categoryHeader = trade->category; } ListBoxData_OpenPosition(hListBox, trade, tickerId); - // Set the decimals for this tickerSymbol. Most will be 2 but futures can have a lot more. - trade->tickerDecimals = GetTickerDecimals(trade->tickerSymbol); - tickerId++; if (tickerId > 500) tickerId = 100; } @@ -208,6 +208,8 @@ void ActiveTrades_ShowActiveTrades() ListBox_SetSel(hListBox, true, curSel); ActiveTrades_ShowListBoxItem(curSel); + RECT rc; GetClientRect(HWND_ACTIVETRADES, &rc); + ActiveTrades_OnSize(HWND_ACTIVETRADES, 0, rc.right, rc.bottom); SetFocus(hListBox); @@ -361,10 +363,11 @@ void ActiveTrades_CalledAwayAssignment( std::shared_ptr trans; std::shared_ptr newleg; - bool isShares = (trade->tickerSymbol.substr(0, 1) == L"/") ? false : true; + bool isShares = (IsFuturesTicker(trade->tickerSymbol)) ? false : true; int QuantityAssigned = 0; int NumLegQuantity = 0; + double multiplier = 1; std::wstring msg = L"Continue with OPTION ASSIGNMENT?\n\n"; @@ -372,11 +375,13 @@ void ActiveTrades_CalledAwayAssignment( QuantityAssigned = min(abs(leg->openQuantity * 100), abs(NumSharesAggregate)); NumLegQuantity = QuantityAssigned / 100; msg += std::to_wstring(QuantityAssigned) + L" shares called away at $" + leg->strikePrice + L" per share."; + multiplier = 1; } else { QuantityAssigned = min(abs(leg->openQuantity), abs(NumFuturesAggregate)); NumLegQuantity = QuantityAssigned; msg += std::to_wstring(QuantityAssigned) + L" futures called away at $" + leg->strikePrice + L" per future."; + multiplier = trade->multiplier; } NumLegQuantity = (leg->openQuantity < 0) ? NumLegQuantity * -1 : NumLegQuantity; @@ -420,8 +425,8 @@ void ActiveTrades_CalledAwayAssignment( trans->description = L"Called away"; trans->underlying = (isShares == true) ? L"SHARES" : L"FUTURES"; trans->quantity = QuantityAssigned; - trans->price = stod(leg->strikePrice); - trans->multiplier = 1; + trans->price = AfxValDouble(leg->strikePrice); + trans->multiplier = multiplier; trans->fees = 0; trade->Transactions.push_back(trans); @@ -435,14 +440,14 @@ void ActiveTrades_CalledAwayAssignment( newleg->action = L"BTC"; newleg->origQuantity = QuantityAssigned; newleg->openQuantity = QuantityAssigned; - trans->total = trans->quantity * trans->price * -1; // DR + trans->total = trans->quantity * multiplier * trans->price * -1; // DR trade->ACB = trade->ACB + trans->total; } else { newleg->action = L"STC"; newleg->origQuantity = QuantityAssigned * -1; newleg->openQuantity = QuantityAssigned * -1; - trans->total = trans->quantity * trans->price; // CR + trans->total = trans->quantity * multiplier * trans->price; // CR trade->ACB = trade->ACB + trans->total; } @@ -477,16 +482,19 @@ void ActiveTrades_Assignment(auto trade, auto leg) bool isShares = (trade->tickerSymbol.substr(0,1) == L"/") ? false : true; int QuantityAssigned = 0; + double multiplier = 1; std::wstring wszLongShort = (leg->PutCall == L"P") ? L"LONG " : L"SHORT "; std::wstring msg = L"Continue with OPTION ASSIGNMENT?\n\n"; if (isShares == true) { QuantityAssigned = abs(leg->openQuantity * 100); + multiplier = 1; msg += wszLongShort + std::to_wstring(QuantityAssigned) + L" shares at $" + leg->strikePrice + L" per share."; } else { QuantityAssigned = abs(leg->openQuantity); + multiplier = trade->multiplier; msg += wszLongShort + std::to_wstring(QuantityAssigned) + L" futures at $" + leg->strikePrice + L" per future."; } @@ -530,8 +538,8 @@ void ActiveTrades_Assignment(auto trade, auto leg) trans->description = L"Assignment"; trans->underlying = (isShares == true) ? L"SHARES" : L"FUTURES"; trans->quantity = QuantityAssigned; - trans->price = stod(leg->strikePrice); - trans->multiplier = 1; + trans->price = AfxValDouble(leg->strikePrice); + trans->multiplier = multiplier; trans->fees = 0; trade->Transactions.push_back(trans); @@ -545,14 +553,14 @@ void ActiveTrades_Assignment(auto trade, auto leg) newleg->action = L"BTO"; newleg->origQuantity = QuantityAssigned; newleg->openQuantity = QuantityAssigned; - trans->total = trans->quantity * trans->price * -1; // DR + trans->total = trans->quantity * multiplier * trans->price * -1; // DR trade->ACB = trade->ACB + trans->total; } else { newleg->action = L"STO"; newleg->origQuantity = QuantityAssigned * -1; newleg->openQuantity = QuantityAssigned * -1; - trans->total = trans->quantity * trans->price; // CR + trans->total = trans->quantity * multiplier * trans->price; // CR trade->ACB = trade->ACB + trans->total; } @@ -673,10 +681,16 @@ void ActiveTrades_RightClickMenu(HWND hListBox, int idx) bool IsTickerLine = false; + // Clear the tdd module global trade variable + tdd.ResetDefaults(); + int nCurSel = ListBox_GetCurSel(hListBox); ListBoxData* ld = (ListBoxData*)ListBox_GetItemData(hListBox, nCurSel); + if (ld->trade == nullptr) return; + trade = ld->trade; tdd.trade = ld->trade; + tdd.trans = ld->trans; tdd.sharesAggregateEdit = ld->AggregateShares; if (nCount == 1) { @@ -726,8 +740,12 @@ void ActiveTrades_RightClickMenu(HWND hListBox, int idx) InsertMenu(hMenu, 0, MF_BYCOMMAND | MF_STRING | MF_ENABLED, (int)TradeAction::AddPutToTrade, L"Add Put to Trade"); InsertMenu(hMenu, 0, MF_BYCOMMAND | MF_STRING | MF_ENABLED, (int)TradeAction::AddCallToTrade, L"Add Call to Trade"); InsertMenu(hMenu, 0, MF_BYCOMMAND | MF_SEPARATOR | MF_ENABLED, (int)TradeAction::NoAction + 3, L""); - InsertMenu(hMenu, 0, MF_BYCOMMAND | MF_STRING | MF_ENABLED, (int)TradeAction::AddSharesToTrade, L"Add Shares to Trade"); - InsertMenu(hMenu, 0, MF_BYCOMMAND | MF_STRING | MF_ENABLED, (int)TradeAction::AddFuturesToTrade, L"Add Futures to Trade"); + + if (IsFuturesTicker(trade->tickerSymbol)) { + InsertMenu(hMenu, 0, MF_BYCOMMAND | MF_STRING | MF_ENABLED, (int)TradeAction::AddFuturesToTrade, L"Add Futures to Trade"); + } else { + InsertMenu(hMenu, 0, MF_BYCOMMAND | MF_STRING | MF_ENABLED, (int)TradeAction::AddSharesToTrade, L"Add Shares to Trade"); + } POINT pt; GetCursorPos(&pt); TradeAction selected = @@ -959,6 +977,9 @@ void ActiveTrades_OnSize(HWND hwnd, UINT state, int cx, int cy) int margin = AfxScaleY(ACTIVETRADES_MARGIN); + // If no entries exist for the ListBox then don't show any child controls + int showflag = (ListBox_GetCount(hListBox) <= 1) ? SWP_HIDEWINDOW : SWP_SHOWWINDOW; + HDWP hdwp = BeginDeferWindowPos(5); // Move and size the top label into place @@ -985,12 +1006,14 @@ void ActiveTrades_OnSize(HWND hwnd, UINT state, int cx, int cy) int nTop = margin; int nHeight = cy - nTop; int nWidth = cx - CustomVScrollBarWidth; - hdwp = DeferWindowPos(hdwp, hListBox, 0, nLeft, nTop, nWidth, nHeight, SWP_NOZORDER | SWP_SHOWWINDOW); + hdwp = DeferWindowPos(hdwp, hListBox, 0, nLeft, nTop, nWidth, nHeight, SWP_NOZORDER | showflag); nLeft = nLeft + nWidth; // right edge of ListBox nWidth = CustomVScrollBarWidth; + int showscrollbar = (bShowScrollBar ? SWP_SHOWWINDOW : SWP_HIDEWINDOW); + if (showflag == SWP_HIDEWINDOW) showscrollbar = SWP_HIDEWINDOW; hdwp = DeferWindowPos(hdwp, hCustomVScrollBar, 0, nLeft, nTop, nWidth, nHeight, - SWP_NOZORDER | (bShowScrollBar ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); + SWP_NOZORDER | showflag); EndDeferWindowPos(hdwp); } diff --git a/IB-Tracker/src/Config/Config.cpp b/IB-Tracker/src/Config/Config.cpp index b44eacd6..b5ec599a 100644 --- a/IB-Tracker/src/Config/Config.cpp +++ b/IB-Tracker/src/Config/Config.cpp @@ -75,10 +75,24 @@ std::unordered_map mapMultipliers { }; std::unordered_map mapTickerDecimals { - { L"/AUD", 5 } + { L"/AUD", 5 }, + { L"/ZB", 3 }, + { L"/ZC", 3 }, + { L"/ZS", 4 } }; + +// ======================================================================================== +// Determine if the incoming ticker symbol is a Future. +// ======================================================================================== +bool IsFuturesTicker(const std::wstring& wszTicker) +{ + return (wszTicker.substr(0, 1) == L"/"); +} + + + // ======================================================================================== // Get the Ticker Decimals for the incoming underlying. // ======================================================================================== diff --git a/IB-Tracker/src/Config/Config.h b/IB-Tracker/src/Config/Config.h index 6ce4957c..1f46892b 100644 --- a/IB-Tracker/src/Config/Config.h +++ b/IB-Tracker/src/Config/Config.h @@ -26,7 +26,7 @@ SOFTWARE. #pragma once -constexpr std::wstring version = L"1.2.1"; +constexpr std::wstring version = L"2.0.0"; bool SaveConfig(); bool LoadConfig(); @@ -41,3 +41,4 @@ std::wstring GetCategoryDescription(int idxCategory); void SetCategoryDescription(int idxCategory, std::wstring wszDescription); bool GetStartupConnect(); void SetStartupConnect(bool bConnect); +bool IsFuturesTicker(const std::wstring& wszTicker); diff --git a/IB-Tracker/src/CustomTextBox/CustomTextBox.cpp b/IB-Tracker/src/CustomTextBox/CustomTextBox.cpp index a1199d67..0b2d4bcd 100644 --- a/IB-Tracker/src/CustomTextBox/CustomTextBox.cpp +++ b/IB-Tracker/src/CustomTextBox/CustomTextBox.cpp @@ -466,6 +466,7 @@ std::wstring CustomTextBox_GetUserData(HWND hCtrl) if (pData != nullptr) { return pData->UserData; } + return L""; } diff --git a/IB-Tracker/src/Database/database.cpp b/IB-Tracker/src/Database/database.cpp index 71efd6be..6522e926 100644 --- a/IB-Tracker/src/Database/database.cpp +++ b/IB-Tracker/src/Database/database.cpp @@ -289,6 +289,7 @@ bool LoadDatabase() leg->action = NumberToAction(try_catch_int(st, 8)); leg->underlying = NumberToUnderlying(try_catch_int(st, 9)); if (trans != nullptr) { + leg->trans = trans; if (trade != nullptr) { // Determine latest date for BP ROI calculation. if (AfxValDouble(wszExpiryDate) > AfxValDouble(trade->BPendDate)) trade->BPendDate = wszExpiryDate; @@ -317,7 +318,6 @@ bool LoadDatabase() trade->ACB = 0; for (const auto trans : trade->Transactions) { trade->ACB = trade->ACB + trans->total; - trade->multiplier = trans->multiplier; } } diff --git a/IB-Tracker/src/Database/trade.cpp b/IB-Tracker/src/Database/trade.cpp index ce491e86..9e5e7f9a 100644 --- a/IB-Tracker/src/Database/trade.cpp +++ b/IB-Tracker/src/Database/trade.cpp @@ -79,8 +79,10 @@ void Trade::createOpenLegsVector() openLegs.clear(); for (const auto &trans : Transactions) { - for (const auto &leg : trans->legs) { + if (trans->multiplier > 0) this->multiplier = trans->multiplier; + for (auto &leg : trans->legs) { if (leg->isOpen()) { + leg->trans = trans; openLegs.push_back(leg); } } diff --git a/IB-Tracker/src/Database/trade.h b/IB-Tracker/src/Database/trade.h index 5748ab85..5ffb94fb 100644 --- a/IB-Tracker/src/Database/trade.h +++ b/IB-Tracker/src/Database/trade.h @@ -36,6 +36,8 @@ SOFTWARE. // +class Transaction; // forward declare + class Leg { @@ -51,6 +53,7 @@ class Leg std::wstring action = L""; // STO,BTO,STC,BTC std::wstring underlying = L""; // OPTIONS, STOCKS, FUTURES bool isOpen(); // method to calc if leg quantity is not zero + std::shared_ptr trans = nullptr; // back pointer to transaction that this leg belongs to }; @@ -83,7 +86,7 @@ class Trade double ACB = 0; double TradeBP = 0; // Buying Power for the entire trade int nextLegID = 0; // Incrementing counter that gets unique ID for legs being generated in TransDetail. - double multiplier = 0; // Updated from Transaction and needed for updatePortfolio real time calculations + double multiplier = 0; // Retrieved from Transaction and needed for updatePortfolio real time calculations double tickerLastPrice = 0; double tickerClosePrice = 0; @@ -95,7 +98,7 @@ class Trade std::wstring OldestTradeTransDate = L"00000000"; // If Trade is closed then this trans will be the BPendDate - std::vector> Transactions; // pointer list for all TransDetail in the trade + std::vector> Transactions; // pointer list for all transactions in the trade std::vector> openLegs; // sorted list of open legs for this trade void setTradeOpenStatus(); diff --git a/IB-Tracker/src/MainWindow/MainWindow.cpp b/IB-Tracker/src/MainWindow/MainWindow.cpp index a21debea..1625b4f3 100644 --- a/IB-Tracker/src/MainWindow/MainWindow.cpp +++ b/IB-Tracker/src/MainWindow/MainWindow.cpp @@ -498,21 +498,6 @@ LRESULT CMainWindow::HandleMessage(UINT msg, WPARAM wParam, LPARAM lParam) return 0; } - - case MSG_CATEGORY_CHANGED: - { - if (HWND_MIDDLEPANEL == ActiveTrades.WindowHandle()) { - // Destroy any existing ListBox line data - // This will also clear the LineData pointers and cancel any previous market data - ListBoxData_DestroyItemData(GetDlgItem(ActiveTrades.WindowHandle(), IDC_TRADES_LISTBOX)); - ActiveTrades_ShowActiveTrades(); - } - if (HWND_MIDDLEPANEL == TransPanel.WindowHandle()) { - TransPanel_ShowTransactions(); - } - return 0; - } - default: return DefWindowProc(m_hwnd, msg, wParam, lParam); } } diff --git a/IB-Tracker/src/MainWindow/tws-client.cpp b/IB-Tracker/src/MainWindow/tws-client.cpp index c00d0650..300ab520 100644 --- a/IB-Tracker/src/MainWindow/tws-client.cpp +++ b/IB-Tracker/src/MainWindow/tws-client.cpp @@ -234,7 +234,9 @@ void tws_performReconciliation() // The results have been loaded into module global resultsText which will be displayed // when Reconcile_Show() is called and Reconcile_positionEnd() has SendMessage notification // to the dialog to say that text is ready. - tws_requestPortfolioUpdates(); + // Load the IBKR and Local positions into the vectors and do the matching + client.cancelPositions(); + client.requestPositions(); // Show the results Reconcile_Show(); @@ -487,14 +489,14 @@ void TwsClient::tickPrice(TickerId tickerId, TickType field, double price, const for (const auto& leg : ld->trade->openLegs) { if (leg->underlying == L"OPTIONS") { if (leg->PutCall == L"P") { - if (ld->trade->tickerLastPrice < std::stod(leg->strikePrice)) { + if (ld->trade->tickerLastPrice < AfxValDouble(leg->strikePrice)) { leg->openQuantity < 0 ? isITMred = true : isITMred = false; leg->openQuantity > 0 ? isITMgreen = true : isITMgreen = false; break; } } else if (leg->PutCall == L"C") { - if (ld->trade->tickerLastPrice > std::stod(leg->strikePrice)) { + if (ld->trade->tickerLastPrice > AfxValDouble(leg->strikePrice)) { leg->openQuantity < 0 ? isITMred = true : isITMred = false; leg->openQuantity > 0 ? isITMgreen = true : isITMgreen = false; break; @@ -560,7 +562,6 @@ void TwsClient::updatePortfolio(const Contract& contract, Decimal position, // Utils::doubleMaxString(marketPrice).c_str(), Utils::doubleMaxString(marketValue).c_str(), Utils::doubleMaxString(averageCost).c_str(), // Utils::doubleMaxString(unrealizedPNL).c_str(), Utils::doubleMaxString(realizedPNL).c_str(), accountName.c_str()); - // Match the incoming contractID with the contractId stored in the Leg. HWND hListBox = GetDlgItem(HWND_ACTIVETRADES, IDC_TRADES_LISTBOX); diff --git a/IB-Tracker/src/Reconcile/Reconcile.cpp b/IB-Tracker/src/Reconcile/Reconcile.cpp index 02bf2630..7a7fb2b9 100644 --- a/IB-Tracker/src/Reconcile/Reconcile.cpp +++ b/IB-Tracker/src/Reconcile/Reconcile.cpp @@ -30,6 +30,7 @@ SOFTWARE. #include "Database/trade.h" #include "Utilities/IntelDecimal.h" #include "Utilities/UserMessages.h" +#include "Config/Config.h" #include "Reconcile.h" @@ -115,12 +116,12 @@ void Reconcile_positionEnd() if (leg->underlying == L"OPTIONS") p.underlying = L"OPT"; if (leg->underlying == L"SHARES") p.underlying = L"STK"; - p.strikePrice = stod(leg->strikePrice); + p.strikePrice = AfxValDouble(leg->strikePrice); p.expiryDate = AfxRemoveDateHyphens(leg->expiryDate); p.PutCall = leg->PutCall; // Check if the ticker is a future - if (p.tickerSymbol.substr(0, 1) == L"/") { + if (IsFuturesTicker(p.tickerSymbol)) { p.tickerSymbol = trade->tickerSymbol.substr(1); if (p.underlying == L"OPT") p.underlying = L"FOP"; } @@ -164,7 +165,6 @@ void Reconcile_positionEnd() } - // (1) Determine what IBKR "real" positions do not exist in the Local database. ResultsText = L"IBKR that do not exist in Local:\r\n"; for (const auto& ibkr : IBKRPositions) { diff --git a/IB-Tracker/src/TradeDialog/TradeDialog.cpp b/IB-Tracker/src/TradeDialog/TradeDialog.cpp index 2b3f7853..14a8a42d 100644 --- a/IB-Tracker/src/TradeDialog/TradeDialog.cpp +++ b/IB-Tracker/src/TradeDialog/TradeDialog.cpp @@ -158,11 +158,8 @@ void TradeDialog_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) std::wstring wszMultiplier = GetMultiplier(tickerSymbol); if (tdd.tradeAction == TradeAction::NewSharesTrade || - tdd.tradeAction == TradeAction::NewFuturesTrade || tdd.tradeAction == TradeAction::ManageShares || - tdd.tradeAction == TradeAction::ManageFutures || - tdd.tradeAction == TradeAction::AddSharesToTrade || - tdd.tradeAction == TradeAction::AddFuturesToTrade) { + tdd.tradeAction == TradeAction::AddSharesToTrade) { wszMultiplier = L"1"; } CustomTextBox_SetText(GetDlgItem(hwnd, IDC_TRADEDIALOG_TXTMULTIPLIER), wszMultiplier); @@ -448,6 +445,9 @@ int TradeDialog_Show(TradeAction inTradeAction) DispatchMessage(&msg); } + // Clear the tdd module global trade variable + tdd.ResetDefaults(); + return DialogReturnCode; } diff --git a/IB-Tracker/src/TradeDialog/TradeDialog.h b/IB-Tracker/src/TradeDialog/TradeDialog.h index 34ca89df..4bbba17c 100644 --- a/IB-Tracker/src/TradeDialog/TradeDialog.h +++ b/IB-Tracker/src/TradeDialog/TradeDialog.h @@ -47,6 +47,14 @@ class TradeDialogData std::shared_ptr trans = nullptr; std::vector< std::shared_ptr > legs; std::wstring sharesAggregateEdit = L"0"; + + void ResetDefaults() { + tradeAction = TradeAction::NoAction; + trade = nullptr; + trans = nullptr; + legs.clear(); + sharesAggregateEdit = L"0"; + } }; extern TradeDialogData tdd; @@ -66,17 +74,18 @@ constexpr int IDC_TRADEDIALOG_TXTFEES = 109; constexpr int IDC_TRADEDIALOG_TXTTOTAL = 110; constexpr int IDC_TRADEDIALOG_COMBODRCR = 111; constexpr int IDC_TRADEDIALOG_TXTTRADEBP = 112; -constexpr int IDC_TRADEDIALOG_LBLSTRATEGY = 113; -constexpr int IDC_TRADEDIALOG_STRATEGY = 114; -constexpr int IDC_TRADEDIALOG_LBLDESCRIBE = 115; -constexpr int IDC_TRADEDIALOG_TXTDESCRIBE = 116; -constexpr int IDC_TRADEDIALOG_LBLEDITWARNING1 = 117; -constexpr int IDC_TRADEDIALOG_LBLEDITWARNING2 = 118; -constexpr int IDC_TRADEDIALOG_LBLEDITWARNING3 = 119; -constexpr int IDC_TRADEDIALOG_LBLEDITWARNING4 = 120; - -constexpr int IDC_TRADEDIALOG_LBLGRIDMAIN = 121; -constexpr int IDC_TRADEDIALOG_LBLGRIDROLL = 122; +constexpr int IDC_TRADEDIALOG_LBLTRADEBP = 113; +constexpr int IDC_TRADEDIALOG_LBLSTRATEGY = 114; +constexpr int IDC_TRADEDIALOG_STRATEGY = 115; +constexpr int IDC_TRADEDIALOG_LBLDESCRIBE = 116; +constexpr int IDC_TRADEDIALOG_TXTDESCRIBE = 117; +constexpr int IDC_TRADEDIALOG_LBLEDITWARNING1= 118; +constexpr int IDC_TRADEDIALOG_LBLEDITWARNING2= 119; +constexpr int IDC_TRADEDIALOG_LBLEDITWARNING3= 120; +constexpr int IDC_TRADEDIALOG_LBLEDITWARNING4= 121; + +constexpr int IDC_TRADEDIALOG_LBLGRIDMAIN = 122; +constexpr int IDC_TRADEDIALOG_LBLGRIDROLL = 123; constexpr int IDC_TRADEDIALOG_LBLTRANSDATE = 125; constexpr int IDC_TRADEDIALOG_CMDTRANSDATE = 126; diff --git a/IB-Tracker/src/TradeDialog/TradeDialogControls.cpp b/IB-Tracker/src/TradeDialog/TradeDialogControls.cpp index 918a0be1..0709f6dc 100644 --- a/IB-Tracker/src/TradeDialog/TradeDialogControls.cpp +++ b/IB-Tracker/src/TradeDialog/TradeDialogControls.cpp @@ -36,6 +36,7 @@ SOFTWARE. #include "MainWindow/tws-client.h" #include "Database/database.h" #include "Category/Category.h" +#include "Config/Config.h" @@ -132,7 +133,7 @@ void TradeDialogControls_ShowFuturesContractDate(HWND hwnd) // Futures Ticker symbols will start with a forward slash character. std::wstring wszTicker = AfxGetWindowText(GetDlgItem(hwnd, IDC_TRADEDIALOG_TXTTICKER)); - int nShow = (wszTicker.substr(0, 1) == L"/") ? SW_SHOW : SW_HIDE; + int nShow = (IsFuturesTicker(wszTicker)) ? SW_SHOW : SW_HIDE; ShowWindow(hCtl1, nShow); ShowWindow(hCtl2, nShow); @@ -195,11 +196,11 @@ void TradeDialog_LoadEditTransactionInTradeTable(HWND hwnd) if (row > 7) break; // QUANTITY (ORIGINAL) - std::wstring legOrigQuantity = std::to_wstring(leg->origQuantity); + std::wstring legOrigQuantity = std::to_wstring(leg->origQuantity / tdd.trans->quantity); TradeGrid_SetColData(hGrid, row, 0, legOrigQuantity); // QUANTITY (OPEN) - std::wstring legOpenQuantity = std::to_wstring(leg->openQuantity); + std::wstring legOpenQuantity = std::to_wstring(leg->openQuantity / tdd.trans->quantity); TradeGrid_SetColData(hGrid, row, 1, legOpenQuantity); // EXPIRY DATE @@ -277,6 +278,18 @@ void TradeDialog_LoadEditLegsInTradeTable(HWND hwnd) } CustomLabel_SetText(GetDlgItem(hwnd, IDC_TRADEDIALOG_LBLTICKER), wszText); CustomTextBox_SetText(GetDlgItem(hwnd, IDC_TRADEDIALOG_TXTTICKER), tdd.trade->tickerSymbol); // hidden + + // Set the multiplier based on the incoming trade. Ensure that multiplier is always 100 for Option + // transactions because it could be set to 1 if the Trade only contains existing Shares. + double multiplier = tdd.trade->multiplier; + if (IsNewOptionsTradeAction(tdd.tradeAction) || + tdd.tradeAction == TradeAction::AddCallToTrade || + tdd.tradeAction == TradeAction::AddPutToTrade || + tdd.tradeAction == TradeAction::AddOptionsToTrade) { + if (IsFuturesTicker(tdd.trade->tickerSymbol) == false) multiplier = 100; + } + CustomTextBox_SetText(GetDlgItem(hwnd, IDC_TRADEDIALOG_TXTMULTIPLIER), std::to_wstring(multiplier)); + CustomTextBox_SetText(GetDlgItem(hwnd, IDC_TRADEDIALOG_TXTTRADEBP), std::to_wstring(tdd.trade->TradeBP)); } @@ -405,8 +418,8 @@ void TradeDialog_LoadEditLegsInTradeTable(HWND hwnd) if (row > 3) break; // QUANTITY - DefaultQuantity = leg->openQuantity; - std::wstring legQuantity = std::to_wstring(leg->openQuantity * -1); + DefaultQuantity = leg->trans->quantity; + std::wstring legQuantity = std::to_wstring(leg->openQuantity / leg->trans->quantity * -1); TradeGrid_SetColData(hGridMain, row, 0, legQuantity); // EXPIRY DATE @@ -446,7 +459,7 @@ void TradeDialog_LoadEditLegsInTradeTable(HWND hwnd) if (row > 3) break; // QUANTITY - std::wstring legQuantity = std::to_wstring(leg->openQuantity); + std::wstring legQuantity = std::to_wstring(leg->openQuantity / leg->trans->quantity); TradeGrid_SetColData(hGridRoll, row, 0, legQuantity); // EXPIRY DATE @@ -474,8 +487,6 @@ void TradeDialog_LoadEditLegsInTradeTable(HWND hwnd) TradeDialog_SetComboDRCR(GetDlgItem(HWND_TRADEDIALOG, IDC_TRADEDIALOG_COMBODRCR), L"DR"); } - // Set the multiplier based on the incoming trade - CustomTextBox_SetText(GetDlgItem(hwnd, IDC_TRADEDIALOG_TXTMULTIPLIER), std::to_wstring(tdd.trade->multiplier)); } @@ -651,7 +662,7 @@ void TradeDialogControls_CreateControls(HWND hwnd) ShowContractExpiry = true; } if (tdd.tradeAction == TradeAction::EditTransaction) { - if (tdd.trade->tickerSymbol.substr(0, 1) == L"/") { // this is a Future + if (IsFuturesTicker(tdd.trade->tickerSymbol)) { // this is a Future wszContractDate = tdd.trade->futureExpiry; ShowContractExpiry = true; } @@ -889,7 +900,7 @@ void TradeDialogControls_CreateControls(HWND hwnd) // TRADE BUYING POWER - CustomLabel_SimpleLabel(hwnd, -1, L"Buying Power", COLOR_WHITEDARK, COLOR_GRAYDARK, + CustomLabel_SimpleLabel(hwnd, IDC_TRADEDIALOG_LBLTRADEBP, L"Buying Power", COLOR_WHITEDARK, COLOR_GRAYDARK, CustomLabelAlignment::MiddleLeft, 580, 310, 100, 23); hCtl = CreateCustomTextBox(hwnd, IDC_TRADEDIALOG_TXTTRADEBP, false, ES_RIGHT, L"0", 580, 337, 80, 23); @@ -897,6 +908,15 @@ void TradeDialogControls_CreateControls(HWND hwnd) CustomTextBox_SetColors(hCtl, COLOR_WHITELIGHT, COLOR_GRAYMEDIUM); CustomTextBox_SetNumericAttributes(hCtl, 2, CustomTextBoxNegative::Allow, CustomTextBoxFormatting::Allow); + if (tdd.tradeAction == TradeAction::NewSharesTrade || + tdd.tradeAction == TradeAction::ManageShares || + tdd.tradeAction == TradeAction::AddSharesToTrade || + tdd.tradeAction == TradeAction::NewFuturesTrade || + tdd.tradeAction == TradeAction::ManageFutures || + tdd.tradeAction == TradeAction::AddFuturesToTrade) { + ShowWindow(GetDlgItem(hwnd, IDC_TRADEDIALOG_LBLTRADEBP), SW_HIDE); + ShowWindow(GetDlgItem(hwnd, IDC_TRADEDIALOG_TXTTRADEBP), SW_HIDE); + } // SAVE button hCtl = CustomLabel_ButtonLabel(hwnd, IDC_TRADEDIALOG_SAVE, L"SAVE", diff --git a/IB-Tracker/src/TradeDialog/TradeDialogSave.cpp b/IB-Tracker/src/TradeDialog/TradeDialogSave.cpp index ef8f1a61..d30bd0d5 100644 --- a/IB-Tracker/src/TradeDialog/TradeDialogSave.cpp +++ b/IB-Tracker/src/TradeDialog/TradeDialogSave.cpp @@ -220,6 +220,12 @@ void TradeDialog_CreateSharesTradeData(HWND hwnd) std::shared_ptr leg = std::make_shared(); leg->underlying = trans->underlying; + // Determine earliest and latest dates for BP ROI calculation. + std::wstring wszDate = AfxRemoveDateHyphens(trans->transDate); + if (AfxValDouble(wszDate) < AfxValDouble(trade->BPstartDate)) trade->BPstartDate = wszDate; + if (AfxValDouble(wszDate) > AfxValDouble(trade->BPendDate)) trade->BPendDate = wszDate; + if (AfxValDouble(wszDate) > AfxValDouble(trade->OldestTradeTransDate)) trade->OldestTradeTransDate = wszDate; + // Set the Share/Futures quantity based on whether Long or Short based on // the IDC_TRADEDIALOG_BUYSHARES or IDC_TRADEDIALOG_SELLSHARES button. @@ -433,7 +439,8 @@ void TradeDialog_CreateOptionsTradeData(HWND hwnd) leg->strikePrice = guiData.legs.at(row).strikePrice; leg->PutCall = guiData.legs.at(row).PutCall; leg->action = guiData.legs.at(row).action; - int intQuantity = guiData.legs.at(row).origQuantity; + leg->trans = trans; + int intQuantity = guiData.legs.at(row).origQuantity * trans->quantity; if (intQuantity == 0) continue; std::wstring wszExpiryDate = AfxRemoveDateHyphens(leg->expiryDate); @@ -482,7 +489,8 @@ void TradeDialog_CreateOptionsTradeData(HWND hwnd) leg->strikePrice = guiData.legsRoll.at(row).strikePrice; leg->PutCall = guiData.legsRoll.at(row).PutCall; leg->action = guiData.legsRoll.at(row).action; - int intQuantity = guiData.legsRoll.at(row).origQuantity; + leg->trans = trans; + int intQuantity = guiData.legsRoll.at(row).origQuantity * trans->quantity; if (intQuantity == 0) continue; std::wstring wszExpiryDate = AfxRemoveDateHyphens(leg->expiryDate); @@ -688,8 +696,8 @@ void TradeDialog_CreateEditTradeData(HWND hwnd) leg->legID = tdd.trade->nextLegID; } - leg->origQuantity = intOrigQuantity; - leg->openQuantity = intOpenQuantity; + leg->origQuantity = intOrigQuantity * tdd.trans->quantity; + leg->openQuantity = intOpenQuantity * tdd.trans->quantity; leg->underlying = tdd.trans->underlying; leg->expiryDate = legExpiry; diff --git a/IB-Tracker/src/TradeGrid/TradeGrid.cpp b/IB-Tracker/src/TradeGrid/TradeGrid.cpp index 1fd91582..a7c5339a 100644 --- a/IB-Tracker/src/TradeGrid/TradeGrid.cpp +++ b/IB-Tracker/src/TradeGrid/TradeGrid.cpp @@ -190,9 +190,6 @@ void TradeGrid_PopulateColumns(TradeGrid* pData) col->hCtl = hCtl; col->idCtrl = idCtrl; col->colType = GridColType::TextBox; - if (pData->bShowOriginalQuantity == false) { - if (row == 0) col->isTriggerCell = true; - } pData->gridCols.push_back(col); idCtrl++; nLeft = nLeft + nWidth + hsp; @@ -470,27 +467,12 @@ void TradeGrid_PopulateTriggerCells(HWND hWnd, auto col) std::wstring wszCellText = TradeGrid_GetText(hWnd, 0, 0); - int intCellQuantity = 0; - if (wszCellText.length()) { - intCellQuantity = abs(stoi(wszCellText)); // will GPF if empty wszCellText string - } - int offset = (pData->bShowOriginalQuantity) ? 1 : 0; std::wstring wszISODate = CustomLabel_GetUserData(pData->gridCols.at(1+offset)->hCtl); std::wstring wszText; for (int i = 1; i < 4; ++i) { - if (col->colType == GridColType::TextBox) { - wszText = TradeGrid_GetText(hWnd, i, 0); - if (wszText.length() != 0) { - int intQuantity = 0; - intQuantity = stoi(wszText); // will GPF if empty wszText string - int intNewQuantity = (intQuantity < 0) ? intCellQuantity * -1 : intCellQuantity; - wszText = std::to_wstring(intNewQuantity); - TradeGrid_SetColData(hWnd, i, 0, wszText); - } - } if (col->colType == GridColType::DatePicker) { wszText = TradeGrid_GetText(hWnd, i, 1); if (wszText.length() != 0) { @@ -498,11 +480,9 @@ void TradeGrid_PopulateTriggerCells(HWND hWnd, auto col) } } } - - CustomTextBox_SetText(GetDlgItem(HWND_TRADEDIALOG, IDC_TRADEDIALOG_TXTQUANTITY), - std::to_wstring(intCellQuantity)); } + // ======================================================================================== // Windows callback function. // ======================================================================================== diff --git a/IB-Tracker/src/TradeHistory/TradeHistory.cpp b/IB-Tracker/src/TradeHistory/TradeHistory.cpp index c0f7132f..2053335d 100644 --- a/IB-Tracker/src/TradeHistory/TradeHistory.cpp +++ b/IB-Tracker/src/TradeHistory/TradeHistory.cpp @@ -34,6 +34,7 @@ SOFTWARE. #include "Transactions/TransDetail.h" #include "Database/trade.h" #include "Utilities/AfxWin.h" +#include "Config/Config.h" #include "TradeHistory.h" @@ -55,6 +56,9 @@ void TradeHistory_ShowTradesHistoryTable(const std::shared_ptr& trade) HWND hListBox = GetDlgItem(HWND_TRADEHISTORY, IDC_HISTORY_LISTBOX); HWND hCustomVScrollBar = GetDlgItem(HWND_TRADEHISTORY, IDC_HISTORY_CUSTOMVSCROLLBAR); HWND hSeparator = GetDlgItem(HWND_TRADEHISTORY, IDC_HISTORY_SEPARATOR); + HWND hSymbol = GetDlgItem(HWND_TRADEHISTORY, IDC_HISTORY_SYMBOL); + HWND hNotesText = GetDlgItem(HWND_TRADEHISTORY, IDC_HISTORY_TXTNOTES); + HWND hNotesLabel = GetDlgItem(HWND_TRADEHISTORY, IDC_HISTORY_LBLNOTES); // Ensure that the Trade History panel is set @@ -64,10 +68,11 @@ void TradeHistory_ShowTradesHistoryTable(const std::shared_ptr& trade) if (trade == nullptr) { // Clear the current trade history table ListBoxData_DestroyItemData(hListBox); - CustomTextBox_SetText(GetDlgItem(HWND_TRADEHISTORY, IDC_HISTORY_TXTNOTES), L""); - CustomLabel_SetText(GetDlgItem(HWND_TRADEHISTORY, IDC_HISTORY_SYMBOL), L""); + CustomTextBox_SetText(hNotesText, L""); + CustomLabel_SetText(hSymbol, L"Trade History"); ListBoxData_AddBlankLine(hListBox); - AfxRedrawWindow(hListBox); + RECT rc; GetClientRect(HWND_TRADEHISTORY, &rc); + TradeHistory_OnSize(HWND_TRADEHISTORY, 0, rc.right, rc.bottom); return; } @@ -76,13 +81,12 @@ void TradeHistory_ShowTradesHistoryTable(const std::shared_ptr& trade) // Prevent ListBox redrawing until all calculations are completed SendMessage(hListBox, WM_SETREDRAW, FALSE, 0); - CustomLabel_SetText( - GetDlgItem(HWND_TRADEHISTORY, IDC_HISTORY_SYMBOL), - trade->tickerSymbol + L": " + trade->tickerName); + + std::wstring wszTicker = trade->tickerSymbol + L": " + trade->tickerName; + if (IsFuturesTicker(trade->tickerSymbol)) wszTicker = wszTicker + L" (" + AfxFormatFuturesDate(trade->futureExpiry) + L")"; + CustomLabel_SetText(hSymbol, wszTicker); - CustomTextBox_SetText( - GetDlgItem(HWND_TRADEHISTORY, IDC_HISTORY_TXTNOTES), - trade->notes); + CustomTextBox_SetText(hNotesText, trade->notes); // Clear the current trade history table @@ -418,6 +422,9 @@ void TradeHistory_OnSize(HWND hwnd, UINT state, int cx, int cy) int margin = AfxScaleY(TRADEHISTORY_MARGIN); + // If no entries exist for the ListBox then don't show any child controls + int showflag = (ListBox_GetCount(hListBox) <= 1) ? SWP_HIDEWINDOW : SWP_SHOWWINDOW; + HDWP hdwp = BeginDeferWindowPos(10); // Move and size the top label into place @@ -446,31 +453,35 @@ void TradeHistory_OnSize(HWND hwnd, UINT state, int cx, int cy) int nTop = margin; int nWidth = cx - CustomVScrollBarWidth; int nHeight = cy - nTop - heightNotesTextBox - heightNotesLabel - AfxScaleY(10); - hdwp = DeferWindowPos(hdwp, hListBox, 0, nLeft, nTop, nWidth, nHeight, SWP_NOZORDER | SWP_SHOWWINDOW); + hdwp = DeferWindowPos(hdwp, hListBox, 0, nLeft, nTop, nWidth, nHeight, SWP_NOZORDER | showflag); nLeft = nLeft + nWidth; // right edge of ListBox nTop = margin; nWidth = CustomVScrollBarWidth; + + int showscrollbar = (bShowScrollBar ? SWP_SHOWWINDOW : SWP_HIDEWINDOW); + if (showflag == SWP_HIDEWINDOW) showscrollbar = SWP_HIDEWINDOW; hdwp = DeferWindowPos(hdwp, hCustomVScrollBar, 0, nLeft, nTop, nWidth, nHeight, - SWP_NOZORDER | (bShowScrollBar ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); + SWP_NOZORDER | showscrollbar); nLeft = 0; nTop = nTop + nHeight; nWidth = cx; hdwp = DeferWindowPos(hdwp, hSeparator, 0, nLeft, nTop, nWidth, nHeight, - SWP_NOZORDER | (bShowScrollBar ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); + SWP_NOZORDER | showscrollbar); nLeft = 0; nTop = cy - heightNotesTextBox - heightNotesLabel; nWidth = cx; - hdwp = DeferWindowPos(hdwp, hNotesLabel, 0, nLeft, nTop, nWidth, heightNotesLabel, SWP_NOZORDER | SWP_SHOWWINDOW); + hdwp = DeferWindowPos(hdwp, hNotesLabel, 0, nLeft, nTop, nWidth, heightNotesLabel, SWP_NOZORDER | showflag); nLeft = 0; nTop = cy - heightNotesTextBox; nWidth = cx; - hdwp = DeferWindowPos(hdwp, hNotesTextBox, 0, nLeft, nTop, nWidth, heightNotesTextBox, SWP_NOZORDER | SWP_SHOWWINDOW); + hdwp = DeferWindowPos(hdwp, hNotesTextBox, 0, nLeft, nTop, nWidth, heightNotesTextBox, SWP_NOZORDER | showflag); EndDeferWindowPos(hdwp); + } @@ -522,7 +533,6 @@ BOOL TradeHistory_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) CustomLabel_SetOptions(hCtl, pData); } - return TRUE; } diff --git a/IB-Tracker/src/TradeHistory/TradeHistory.h b/IB-Tracker/src/TradeHistory/TradeHistory.h index 842432a2..96428a9c 100644 --- a/IB-Tracker/src/TradeHistory/TradeHistory.h +++ b/IB-Tracker/src/TradeHistory/TradeHistory.h @@ -50,7 +50,7 @@ constexpr int IDC_HISTORY_TXTNOTES = 119; constexpr int HISTORY_LISTBOX_ROWHEIGHT = 20; constexpr int TICKER_TOTALS_LISTBOX_ROWHEIGHT = 16; -constexpr int TRADEHISTORY_WIDTH = 400; +constexpr int TRADEHISTORY_WIDTH = 440; constexpr int TRADEHISTORY_MARGIN = 24; void TradeHistory_ShowTradesHistoryTable(const std::shared_ptr& trade); diff --git a/IB-Tracker/src/Utilities/ListBoxData.cpp b/IB-Tracker/src/Utilities/ListBoxData.cpp index ca29b327..a4dff88d 100644 --- a/IB-Tracker/src/Utilities/ListBoxData.cpp +++ b/IB-Tracker/src/Utilities/ListBoxData.cpp @@ -497,7 +497,7 @@ void ListBoxData_OpenPosition(HWND hListBox, const std::shared_ptr& trade COLOR_WHITEDARK, font8, FontStyleRegular); ld->SetData(1, trade, tickerId, trade->tickerSymbol, StringAlignmentNear, StringAlignmentCenter, COLOR_GRAYDARK, COLOR_WHITELIGHT, font9, FontStyleRegular | FontStyleBold); - // Col 1 to 6 are set based on incoming TWS price data + ld->SetData(COLUMN_TICKER_ITM, trade, tickerId, L"", StringAlignmentNear, StringAlignmentCenter, COLOR_GRAYDARK, COLOR_WHITELIGHT, font8, FontStyleRegular); // ITM ld->SetData(3, trade, tickerId, L"", StringAlignmentNear, StringAlignmentCenter, COLOR_GRAYDARK, @@ -511,15 +511,6 @@ void ListBoxData_OpenPosition(HWND hListBox, const std::shared_ptr& trade COLOR_WHITELIGHT, font9, FontStyleRegular | FontStyleBold); // current price ld->SetData(COLUMN_TICKER_PERCENTCHANGE, trade, tickerId, L"", StringAlignmentNear, StringAlignmentCenter, COLOR_GRAYDARK, COLOR_WHITEDARK, font8, FontStyleRegular); // price percentage change - - //ld->SetData(COLUMN_TICKER_AVGPX, trade, tickerId, L"0.00", StringAlignmentFar, StringAlignmentCenter, COLOR_GRAYDARK, - // COLOR_WHITEDARK, font8, FontStyleRegular); // Book Value and average Price - //ld->SetData(COLUMN_TICKER_LASTPX, trade, tickerId, L"0.00", StringAlignmentFar, StringAlignmentCenter, COLOR_GRAYDARK, - // COLOR_WHITEDARK, font8, FontStyleRegular); // Market Value and Last Price - //ld->SetData(COLUMN_TICKER_PERCENTCOMPLETE, trade, tickerId, L"0.00%", StringAlignmentFar, StringAlignmentCenter, COLOR_GRAYDARK, - // COLOR_WHITEDARK, font8, FontStyleRegular); // Percentage values for the previous two columns data - //ld->SetData(COLUMN_TICKER_UPNL, trade, tickerId, L"0.00", StringAlignmentFar, StringAlignmentCenter, COLOR_GRAYDARK, - // COLOR_WHITEDARK, font8, FontStyleRegular); // Unrealized profit or loss } ListBox_AddString(hListBox, ld); @@ -535,7 +526,7 @@ void ListBoxData_OpenPosition(HWND hListBox, const std::shared_ptr& trade - // *** SHARES *** + // *** SHARES/FUTURES *** // Roll up all of the SHARES or FUTURES Transactions and display the aggregate rather than the individual legs. std::wstring textShares; int aggregate = 0; @@ -565,7 +556,10 @@ void ListBoxData_OpenPosition(HWND hListBox, const std::shared_ptr& trade col++; if (textShares == L"SHARES") ld->lineType = LineType::Shares; - if (textShares == L"FUTURES") ld->lineType = LineType::Futures; + if (textShares == L"FUTURES") { + ld->lineType = LineType::Futures; + textShares = textShares + L": " + AfxFormatFuturesDate(trade->futureExpiry); + } ld->SetData(col, trade, tickerId, textShares, StringAlignmentNear, StringAlignmentCenter, COLOR_GRAYMEDIUM, COLOR_WHITEDARK, font8, FontStyleRegular); @@ -579,6 +573,12 @@ void ListBoxData_OpenPosition(HWND hListBox, const std::shared_ptr& trade COLOR_WHITEDARK, font8, FontStyleRegular); col++; + if (isHistory) { + ld->SetData(col, trade, tickerId, L"", StringAlignmentNear, StringAlignmentCenter, COLOR_GRAYMEDIUM, + COLOR_WHITEDARK, font8, FontStyleRegular); + col++; + } + text = AfxMoney(std::abs(trade->ACB / aggregate)); ld->SetData(col, trade, tickerId, text, StringAlignmentCenter, StringAlignmentCenter, COLOR_GRAYMEDIUM, COLOR_WHITEDARK, font8, FontStyleRegular); @@ -737,7 +737,7 @@ void ListBoxData_HistoryHeader(HWND hListBox, const std::shared_ptr& trad // ======================================================================================== -// Create the display data for a History SHARES leg. +// Create the display data for a History SHARES/FUTURES leg. // ======================================================================================== void ListBoxData_HistorySharesLeg( HWND hListBox, const std::shared_ptr& trade, const std::shared_ptr& trans, const std::shared_ptr& leg) @@ -750,11 +750,15 @@ void ListBoxData_HistorySharesLeg( ld->SetData(2, trade, tickerId, trans->underlying, StringAlignmentNear, StringAlignmentCenter, COLOR_GRAYMEDIUM, COLOR_WHITEDARK, font8, FontStyleRegular); - for (int i = 3; i < 7; i++) { + for (int i = 3; i < 6; i++) { ld->SetData(i, trade, tickerId, L"", StringAlignmentNear, StringAlignmentCenter, COLOR_GRAYMEDIUM, COLOR_WHITEDARK, font8, FontStyleRegular); } + std::wstring wszText = AfxMoney(trans->price, false, trade->tickerDecimals); + ld->SetData(6, trade, tickerId, wszText, StringAlignmentFar, StringAlignmentCenter, + COLOR_GRAYMEDIUM, COLOR_WHITEDARK, font8, FontStyleRegular); + ld->SetData(7, trade, tickerId, std::to_wstring(leg->openQuantity), StringAlignmentFar, StringAlignmentCenter, COLOR_GRAYMEDIUM, COLOR_WHITEDARK, font8, FontStyleRegular); @@ -882,7 +886,9 @@ void ListBoxData_OutputClosedPosition(HWND hListBox, const std::shared_ptrSetData(2, trade, tickerId, trade->tickerSymbol, StringAlignmentNear, StringAlignmentCenter, COLOR_GRAYDARK, COLOR_WHITELIGHT, font8, FontStyleRegular); - ld->SetData(3, trade, tickerId, trade->tickerName, StringAlignmentNear, StringAlignmentCenter, + std::wstring wszTickerName = trade->tickerName; + if (IsFuturesTicker(trade->tickerSymbol)) wszTickerName = wszTickerName + L" (" + AfxFormatFuturesDate(trade->futureExpiry) + L")"; + ld->SetData(3, trade, tickerId, wszTickerName, StringAlignmentNear, StringAlignmentCenter, COLOR_GRAYDARK, COLOR_WHITELIGHT, font8, FontStyleRegular); DWORD clr = (trade->ACB >= 0) ? COLOR_GREEN : COLOR_RED; diff --git a/IB-Tracker/src/Utilities/UserMessages.h b/IB-Tracker/src/Utilities/UserMessages.h index 06401492..84db6471 100644 --- a/IB-Tracker/src/Utilities/UserMessages.h +++ b/IB-Tracker/src/Utilities/UserMessages.h @@ -66,8 +66,7 @@ constexpr int MSG_TWS_CONNECT_DISCONNECT = WM_USER + 1006; constexpr int MSG_TWS_WARNING_EXCEPTION = WM_USER + 1007; constexpr int MSG_STARTUP_SHOWTRADES = WM_USER + 1008; constexpr int MSG_DATEPICKER_DATECHANGED = WM_USER + 1009; -constexpr int MSG_CATEGORY_CHANGED = WM_USER + 1010; -constexpr int MSG_RECONCILIATION_READY = WM_USER + 1011; +constexpr int MSG_RECONCILIATION_READY = WM_USER + 1010; constexpr int DIALOG_RETURN_OK = 0; constexpr int DIALOG_RETURN_CANCEL = 1; \ No newline at end of file diff --git a/README.md b/README.md index 4ee4fd00..2937c826 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ I wrote this program because tracking trades and their corresponding transaction * Easy to learn and very intuitive with all information available on the main screen. * Portable. You can easily run the program from a thumb drive. No intrusive install or uninstall procedures. * High DPI aware. Works and looks great on monitors of all sizes, resolutions and font scalings. -* Small (about 483K), fast (written in C++), and self-contained (no external dependencies). +* Small (about 485K), fast (written in C++), and self-contained (no external dependencies). * Simple text file "database" that can easily be manually edited if needed. No database engine needed. * The only pain point is that you have to manually enter your transactions into IB-Tracker in order to ensure that transactions are grouped with the correct trades. However, there is a "Reconcile" functionality that ensures that your local data always matches what exists in IBKR/TWS. * Currently, only Windows compatible (Windows 10 and Windows 11). May work on older Windows versions but not guaranteed. It will work on Linux using Wine but you may experience some visual glitches due to the font family Unicode characters that the program uses.