CLAUDE.md - AI Assistant Guide for FXO AI Translator
Guides an AI assistant through a.NET Windows Forms app that parses FX options trade requests, generates OVML and UBS formats, and integrates with Bloomberg and GFI Fenics via FIX.
What this file does
Guides an AI assistant through a.NET Windows Forms app that parses FX options trade requests, generates OVML and UBS formats, and integrates with Bloomberg and GFI Fenics via FIX.
When to use it
- Onboarding a new AI assistant to the FXO AI Translator codebase
- Debugging trade parsing failures or FIX message rejections
- Adding a new trade pattern, currency pair, or multi-leg structure
- Modifying FIX message field ordering for GFI compliance
Assumes this stack
CLAUDE.md - AI Assistant Guide for FXO AI Translator
Last Updated: 2025-11-27 Target Audience: AI assistants working on this codebase Project: FX Options AI Translator with Bloomberg & GFI Integration
Table of Contents
- Project Overview
- Architecture & Design Patterns
- Project Structure
- Key Components
- Development Workflows
- Coding Conventions
- Integration Points
- Common Tasks
- Critical Knowledge
- Testing & Debugging
- Git Workflow
Project Overview
Purpose
FXO AI Translator is a sophisticated Windows Forms application that converts natural language FX options trade requests into structured formats (OVML for Bloomberg Terminal and UBS format) and integrates with GFI Fenics via FIX protocol for trade execution.
Technology Stack
- .NET 8.0 (Windows Forms)
- Bloomberg Desktop API (
Bloomberglp.Blpapi.dll) - QuickFix.Net (FIX 4.4 protocol)
- OpenAI API (GPT-4o-mini for NLP)
- QLNet (Quantitative finance library)
Key Capabilities
- Natural Language Parsing: English, Swedish, Norwegian
- 3-Tier Parsing Strategy: Regex → Learned Patterns → AI Fallback
- Live Market Data: Bloomberg API spot rates
- Trade Automation: Auto-send OVML to Bloomberg Terminal
- FIX Integration: Quote requests and execution via GFI Fenics
- Pattern Learning: System learns from successful AI parses
Architecture & Design Patterns
Overall Architecture
┌─────────────────────────────────────────────────────────────┐
│ User Interface │
│ MainForm.cs - Trade Blotter, Speech Input, Clipboard │
└──────────────────────┬──────────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────────────┐
│ Parsing Engine │
│ TradeParser.cs (Orchestrator) │
│ ├─ RegexTradePatterns.cs (20+ patterns) │
│ ├─ OpenAIService.cs (AI + Pattern Learning) │
│ └─ TradeSanityChecker.cs (Validation) │
└───────┬─────────────────────────────────┬──────────────────┘
│ │
┌───────▼──────────┐ ┌──────────▼─────────────────┐
│ Bloomberg API │ │ FXOptionsSimulator │
│ (Market Data & │ │ (GFI FIX Integration) │
│ OVML Execution) │ │ - TradeStructure │
└──────────────────┘ │ - GFIFIXSessionManager │
│ - RawFIXMessageBuilder │
│ - TradeBlotter │
└────────────────────────────┘
Design Patterns Used
- Strategy Pattern: Parsing pipeline (Regex → Learned → AI)
- Singleton Pattern:
TradeBlotter,GlobalFIXSession - Builder Pattern:
RawFIXMessageBuilderfor FIX messages - Observer Pattern: FIX message handlers, UI events
- Factory Pattern: Pattern matching in
RegexTradePatterns
Key Architectural Decisions
- Raw FIX Messages: GFI requires specific field ordering; QuickFix sorts by tag number, so we use raw message construction
- Hybrid Intelligence: Regex for speed, AI for flexibility, learned patterns for optimization
- Dual Output: Both OVML (Bloomberg) and UBS formats generated simultaneously
- Date Policy Canonicalization: Tag 75 = TODAY, Tag 5020 = T+1 premium settlement
- Premium-Based Execution: Recent commits show preference for premium (Tag 6436) over volatility (Tag 5678)
Project Structure
FXOAiTranslate/
├── Core Application (Windows Forms)
│ ├── MainForm.cs (1,471 lines) - Main UI with trade blotter
│ ├── Program.cs - Entry point with debug console
│ ├── App.config - OpenAI API key configuration
│ └── quickfix.cfg - FIX session configuration
│
├── Parsing Engine
│ ├── TradeParser.cs (1,386 lines) - Main parsing orchestrator
│ ├── RegexTradePatterns.cs (302 lines) - 20+ pattern definitions
│ ├── TradeSanityChecker.cs (394 lines) - OVML validation logic
│ └── OpenAIService.cs (709 lines) - AI integration + pattern learning
│
├── Market Data Integration
│ └── BloombergService.cs (293 lines) - Bloomberg Terminal integration
│
├── FXOptionsSimulator/ (Separate Project)
│ ├── TradeStructure.cs - Trade object models
│ ├── TradeBlotter.cs - Singleton trade tracker
│ ├── TradeBlotterForm.cs - Trade blotter UI
│ ├── GFIQuoteDialog.cs - Quote request/response UI
│ ├── FenicsConfig.cs - GFI LP configurations
│ ├── OVMLBridge.cs - OVML ↔ TradeStructure converter
│ ├── FxDateService.cs - FX date calculations
│ ├── DatePolicy.cs - Business day conventions
│ └── FIX/
│ ├── GFIFIXSessionManager.cs - FIX session lifecycle
│ ├── GFIFIXApplication.cs - FIX message handlers
│ └── RawFIXMessageBuilder.cs - Raw FIX message construction
│
└── Documentation/
├── README.md
└── BGC__GFI_FIX_Specification_for_FX_v1_4_4.pdf
Key Components
1. MainForm.cs (1,471 lines)
Primary Responsibilities:
- UI management (DataGridView trade blotter)
- Trade processing pipeline with async/await
- Speech recognition integration
- Clipboard monitoring (Ctrl+V paste-anywhere)
- Trade persistence (JSON in AppData)
- Bloomberg auto-send functionality
Key Methods:
ProcessTradeAsync()- Main entry point for trade processingLoadTrades()/SaveTrades()- JSON persistenceSendToBloomberg()- Automated OVML command executionUpdateRowColors()- Color-coded parse method indicators
UI Features:
- Color coding: Green=Regex, Yellow=Learned, Blue=AI, Orange=Warning, Red=Error
- Context menu: Copy OVML/UBS, Re-parse with AI, Delete, Send to GFI
- Filter toggle: Today's trades vs All
- Status bar: Bloomberg connection, processing indicator
2. TradeParser.cs (1,386 lines)
Primary Responsibilities:
- Orchestrates 3-tier parsing strategy
- Date and tenor extraction (multi-language)
- Currency pair detection (24 pairs)
- Spot rate integration
- OVML and UBS format generation
- Result caching
Parsing Pipeline:
Input → Preprocess → Check Cache → Regex → Learned → AI → Validate → Generate → Cache
Key Methods:
ParseTradeAsync()- Main orchestratorExtractCurrencyPair()- Recognizes 24 CCY pairsExtractExpiry()- Multi-format date parsingTryParseWithRegex()- Pattern matching (20+ patterns)TryParseWithLearnedPatterns()- Similarity matching (60% threshold)ParseWithAI()- OpenAI fallbackGenerateUBSFormat()- Convert OVML → UBS
Multi-Language Support:
- English: buy, sell, call, put
- Swedish: köpa, sälja
- Norwegian: kjøp, selg
3. BloombergService.cs (293 lines)
Primary Responsibilities:
- Bloomberg Terminal window detection
- OVML command automation (keyboard simulation)
- Live spot rate fetching via Bloomberg API
- Connection status monitoring
Key Methods:
SendOVMLAsync()- Send OVML to TerminalFetchSpotRateAsync()- Get live spot via APIIsBloombergConnected()- Check bplus.exe process
Bloomberg Automation:
- Find OVML window (exclude browser windows)
- Activate window
- Copy OVML to clipboard
- Send: Ctrl+T (clear) → Ctrl+V (paste) → Enter
4. OpenAIService.cs (709 lines)
Dual Purpose: AI Parser + Pattern Learner
AI Integration:
- Model: GPT-4o-mini (cost-effective)
- Temperature: 0.1 (deterministic)
- Max Tokens: 500
- Comprehensive 314-line system prompt with OVML rules
Pattern Learning:
- Stores successful AI parses as learned patterns
- Similarity matching: 60% token overlap threshold
- JSON persistence:
learned_patterns.json - Cache for repeated inputs
Key Methods:
ParseTradeWithAIAsync()- OpenAI API callTryGetLearnedPattern()- Similarity searchAddLearnedPattern()- Store successful parseCalculateSimilarity()- Token-based matching
5. TradeSanityChecker.cs (394 lines)
Validation Logic:
- OVML structure validation
- Multi-leg consistency checks
- Spread direction validation
- Expiry date validation (no past dates)
- Confidence scoring (0.9 perfect, 0.75 warnings, 0.1 errors)
Key Methods:
ValidateTrade()- Main entry pointValidateBasicStructure()- Format checksValidateMultiLeg()- Leg count matchingValidateSpreadDirection()- Put/Call spread rulesCheckExpiryDate()- Date validation
6. RegexTradePatterns.cs (302 lines)
20+ Regex Patterns:
Vanilla_CurrencyLed- "EURNOK 17Dec25 9.85 call 25M"Collar_BuyCallSellCallSellPut- 3-leg structureSeagull_BuyPutSellPutSellCall- 3-leg protectionPutSpread_DifferentNotionals- Unequal notionalsCallSpread_DifferentNotionals- Unequal notionalsRiskReversal_PutCall/RiskReversal_CallPutStraddle/StranglepatternsSimple_Vanilla- Fallback pattern
Pattern Structure:
public static (string Pattern, string Name, int Priority) PatternName()
{
return (@"regex_pattern", "PatternName", priority);
}
7. GFIFIXSessionManager.cs
FIX Session Lifecycle:
- Session creation and configuration
- Logon/Logout handling
- Connection monitoring
- Message routing
Key Methods:
StartSession()- Initialize FIX connectionSendQuoteRequest()- Request quote from LPSendNewOrderMultileg()- Execute tradeCancelQuote()- Cancel pending quote
8. RawFIXMessageBuilder.cs
Critical Component for GFI Compliance:
GFI requires specific field ordering that QuickFix doesn't preserve. This builder constructs raw FIX messages with exact field order.
Key Methods:
BuildQuoteRequest()- Construct 35=R messageBuildNewOrderMultileg()- Construct 35=AB messageBuildQuoteCancel()- Construct 35=Z message
Field Ordering Example:
Tag 75 (TradeDate) MUST come before Tag 5020 (PremiumDelivery)
Tag 6120 (NoMQEntries) MUST precede repeating groups
Repeating groups must maintain strict field order within each block
Date Policy Canonicalization:
- Tag 75: TODAY (yyyyMMdd format)
- Tag 5020: T+1 premium delivery
9. TradeStructure.cs
Trade Object Model:
public class TradeStructure
{
public string Underlying { get; set; } // "EURNOK"
public DateTime Expiry { get; set; } // 2025-12-17
public List<TradeLeg> Legs { get; set; } // 1-3 legs
public string StructureType { get; set; } // "1" (Vanilla), "5" (RR), etc.
public double SpotReference { get; set; } // 10.9518
}
public class TradeLeg
{
public string Direction { get; set; } // "BUY" / "SELL"
public string OptionType { get; set; } // "CALL" / "PUT"
public double Strike { get; set; } // 9.8500
public double NotionalMM { get; set; } // 25.0
}
10. OVMLBridge.cs
OVML ↔ TradeStructure Converter:
- Parses OVML strings into TradeStructure objects
- Extracts legs, strikes, notionals
- Handles multi-leg structures
- Detects structure types
Key Methods:
ConvertToTradeStructure()- Parse OVML → TradeStructureConvertToOVML()- TradeStructure → OVML string
Development Workflows
Adding a New Trade Pattern
- Define Pattern in RegexTradePatterns.cs:
public static (string Pattern, string Name, int Priority) MyNewPattern()
{
string pattern = @"(?<action>buy|sell)\s+(?<notional>[\d.]+)M\s+(?<ccy>[A-Z]{6})\s+(?<strike>[\d.]+)\s+(?<type>call|put)";
return (pattern, "MyNewPattern", 100); // Higher priority = checked first
}
- Add to Pattern List in TradeParser.cs:
patterns.Add(RegexTradePatterns.MyNewPattern());
- Test with Sample Inputs:
var result = await _tradeParser.ParseTradeAsync("buy 10M EURUSD 1.10 call");
Assert.AreEqual("Regex", result.ParseMethod);
- Add Validation Logic (if needed) in TradeSanityChecker.cs
Modifying FIX Message Structure
⚠️ CRITICAL: Field order matters for GFI
- Read Specification:
Documentation/BGC__GFI_FIX_Specification_for_FX_v1_4_4.pdf - Modify RawFIXMessageBuilder.cs: Add fields in exact order
- Test with GFI Test Environment: Verify message acceptance
- Log Full Messages: Use
Console.WriteLine(rawMessage)to debug - Verify Tag Values: Check GFI documentation for valid values
Example - Adding a New Field:
// WRONG - QuickFix sorts by tag number
message.SetField(new QuickFix.Fields.CustomTag(9999, "value"));
// CORRECT - Raw message with explicit ordering
sb.Append("8=FIX.4.4|9=XXX|35=R|...|9999=value|...|10=XXX|");
Adding Bloomberg Fields
- Check Bloomberg API Documentation for field names
- Modify BloombergService.cs:
Element securities = request.GetElement("securities");
securities.AppendValue("EURUSD Curncy");
request.Set("fields", new string[] { "PX_LAST", "NEW_FIELD" });
- Handle Response:
if (fieldData.HasElement("NEW_FIELD"))
{
double value = fieldData.GetElementAsFloat64("NEW_FIELD");
}
Extending AI Prompt
- Modify OpenAIService.cs -
BuildSystemPrompt()method - Add Examples: Include input/output pairs
- Add Rules: Specify new parsing rules
- Test with Edge Cases: Verify AI understands new requirements
- Monitor Token Usage: Keep prompt under 1000 tokens
Coding Conventions
Naming Conventions
// Classes: PascalCase
public class TradeParser { }
// Methods: PascalCase
public async Task<TradeResult> ParseTradeAsync() { }
// Private fields: _camelCase with underscore
private readonly BloombergService _bloombergService;
// UI controls: Type prefix
private DataGridView dgvTradeBlotter;
private TextBox txtManualInput;
private CheckBox chkAutoSend;
// Constants: UPPER_SNAKE_CASE
private const int MAX_RETRY_ATTEMPTS = 3;
// Local variables: camelCase
string currencyPair = "EURUSD";
Code Organization
// Class member order:
1. Constants
2. Static fields
3. Private fields
4. Properties
5. Constructors
6. Public methods
7. Private methods
8. Event handlers
9. Nested classes
// File organization:
- One class per file (except nested classes)
- Filename matches class name
- Using statements at top, grouped and sorted
Async/Await Patterns
// Good - Proper async naming and usage
public async Task<TradeResult> ParseTradeAsync(string input)
{
var result = await _openAIService.ParseTradeWithAIAsync(input);
return result;
}
// Good - Avoid async void except event handlers
private async void btnParse_Click(object sender, EventArgs e)
{
try
{
await ProcessTradeAsync();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Error Handling
// Specific exceptions first, general last
try
{
await ProcessTradeAsync();
}
catch (BloombergConnectionException ex)
{
LogError("Bloomberg connection failed", ex);
ShowUserError("Please ensure Bloomberg Terminal is running");
}
catch (FIXSessionException ex)
{
LogError("FIX session error", ex);
ShowUserError("GFI connection lost. Reconnecting...");
}
catch (Exception ex)
{
LogError("Unexpected error", ex);
ShowUserError("An unexpected error occurred");
}
Logging Standards
// Console logging for debug (Program.cs allocates console)
Console.WriteLine($"[TRACE] {DateTime.Now:HH:mm:ss.fff} | ParseTrade | Input: {input}");
// Color-coded console output
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("SUCCESS: Trade parsed");
Console.ResetColor();
// UI debug log panel
AppendLog($"[{DateTime.Now:HH:mm:ss}] Parsing: {input}");
Integration Points
Bloomberg Terminal Integration
Prerequisites:
- Bloomberg Terminal must be running
- Desktop API must be enabled
Bloomberglp.Blpapi.dllreferenced
Connection Detection:
bool isConnected = Process.GetProcessesByName("bplus").Any();
Window Automation:
- Find OVML window:
FindWindow(null, "OVML") - Exclude browser windows: Check class name
- Send commands: Win32 API keyboard simulation
Market Data:
// Request spot rate
var spotRate = await _bloombergService.FetchSpotRateAsync("EURUSD");
// Returns: 1.0895 (PX_LAST field)
⚠️ Important Notes:
- Bloomberg API requires licensed terminal
- Window detection may fail if OVML window title changes
- Keyboard simulation requires active window focus
OpenAI API Integration
Configuration:
<!-- App.config -->
<appSettings>
<add key="OpenAIApiKey" value="sk-..." />
</appSettings>
API Call:
var response = await _openAI.Chat.CreateChatCompletionAsync(new ChatRequest
{
Model = "gpt-4o-mini",
Temperature = 0.1,
MaxTokens = 500,
Messages = new List<ChatMessage>
{
new ChatMessage { Role = "system", Content = systemPrompt },
new ChatMessage { Role = "user", Content = userInput }
}
});
Cost Optimization:
- Model: gpt-4o-mini (cheaper than gpt-4)
- Temperature: 0.1 (deterministic, fewer retries)
- MaxTokens: 500 (limit response length)
- Caching: Avoid duplicate API calls
⚠️ Important Notes:
- API key must be kept secure
- Rate limiting may occur
- Graceful fallback if API unavailable
- Pattern learning reduces API calls over time
GFI Fenics FIX Integration
Connection Architecture:
Application → QuickFix Session → SSLTunnelProxy (localhost:9443) → GFI Server
Configuration:
# quickfix.cfg
[DEFAULT]
ConnectionType=initiator
ReconnectInterval=30
FileStorePath=fix_store
FileLogPath=fix_logs
[SESSION]
BeginString=FIX.4.4
SenderCompID=YOUR_SENDER_ID
TargetCompID=GFI_TARGET_ID
SocketConnectHost=localhost
SocketConnectPort=9443
DataDictionary=FIX44.xml
Message Flow:
- Quote Request (35=R):
User clicks "Get Quote" → TradeStructure → BuildQuoteRequest() → Send
- Quote Response (35=S):
GFI sends quote → GFIFIXApplication.OnMessage() → Parse BID/OFFER → Update UI
- Order Execution (35=AB):
User selects BID/OFFER → BuildNewOrderMultileg() → Send
- Execution Report (35=8):
GFI confirms fill → Update TradeBlotter → Show success message
Critical Custom Tags:
- Tag 5020: Premium Delivery (canonical = T+1)
- Tag 5235: Expiry Date (yyyyMMdd format)
- Tag 5678: Volatility
- Tag 5844: Leg Premium Price
- Tag 6035: Number of Legs
- Tag 6120: NoMQEntries (repeating group count)
- Tag 6436: Premium (BID/OFFER pricing) ← PRIMARY PRICING FIELD
- Tag 7940: Structure Type (1=Vanilla, 5=RR, 8=Call Spread, 9=Put Spread, 10=Seagull)
- Tag 9904: Lot Size Multiplier
⚠️ CRITICAL GOTCHAS:
- Field Ordering: GFI rejects messages with incorrect field order
- QuoteID Handling: Use EXACT QuoteID from quote (don't transform)
- BID quotes end with
-O - OFFER quotes end with
-T
- BID quotes end with
- Date Policy: Tag 75 = TODAY, Tag 5020 = T+1 (canonical dates)
- Premium vs Volatility: Use Tag 6436 (Premium) for execution logic, not Tag 5678 (Volatility)
- Repeating Groups: Tag 6120 must precede leg groups, each leg must have all required fields
Recent Debug Focus:
- Premium consistency between Tag 6436 and Tag 5844
- QuoteID suffix handling (-O for BID, -T for OFFER)
- Best offer detection: Maximum (least negative) premium
Common Tasks
Task 1: Debug Why a Trade Isn't Parsing
Step-by-Step:
- Check Console Output: See which patterns were tried
- Test Each Pattern Manually:
var pattern = RegexTradePatterns.Vanilla_CurrencyLed();
var match = Regex.Match(input, pattern.Pattern, RegexOptions.IgnoreCase);
Console.WriteLine($"Match: {match.Success}");
foreach (Group group in match.Groups)
{
Console.WriteLine($"{group.Name}: {group.Value}");
}
- Check Preprocessing: Input might be modified before pattern matching
string preprocessed = PreprocessInput(input);
Console.WriteLine($"Original: {input}");
Console.WriteLine($"Preprocessed: {preprocessed}");
- Test AI Fallback:
var aiResult = await _openAIService.ParseTradeWithAIAsync(input);
Console.WriteLine($"AI Result: {aiResult.OVML}");
- Check Validation:
var validation = _sanityChecker.ValidateTrade(ovml, input);
Console.WriteLine($"Valid: {validation.IsValid}, Confidence: {validation.Confidence}");
foreach (var error in validation.Errors)
{
Console.WriteLine($"Error: {error}");
}
Task 2: Add Support for a New Currency Pair
- Add to commonPairs array in TradeParser.cs:
private static readonly string[] commonPairs = new[]
{
"EURUSD", "USDJPY", "GBPUSD", "AUDUSD", "USDCAD", "USDCHF",
"NZDUSD", "EURGBP", "EURJPY", "GBPJPY", "EURCHF", "AUDJPY",
"EURAUD", "EURNOK", "EURSEK", "USDNOK", "USDSEK", "USDTRY",
"USDMXN", "USDZAR", "EURCAD", "AUDNZD", "NOKSEK", "EURTRY",
"NEWPAIR" // Add here
};
- Test Bloomberg Integration:
var spot = await _bloombergService.FetchSpotRateAsync("NEWPAIR");
// Verify Bloomberg returns valid spot rate
- Test with Sample Trade:
var result = await ParseTradeAsync("buy 10M NEWPAIR 3M 1.5000 call");
Task 3: Fix a FIX Message Rejection
Common Rejection Reasons:
-
Incorrect Field Order:
- Check
RawFIXMessageBuilder.cs - Compare with GFI specification PDF
- Use Wireshark to capture accepted messages from other systems
- Check
-
Invalid Tag Values:
- Check GFI specification for valid values
- Example: Tag 7940 (Structure Type) must be 1, 5, 8, 9, or 10
-
Missing Required Fields:
- Check session logs in
fix_logs/ - Look for reject messages (35=3)
- Add missing fields in correct order
- Check session logs in
-
Date Format Issues:
- Ensure Tag 75 is yyyyMMdd (e.g., "20251217")
- Ensure Tag 5235 is yyyyMMdd
- Check timezone handling
Debug Process:
// Add detailed logging in RawFIXMessageBuilder.cs
Console.WriteLine($"[FIX OUT] {rawMessage.Replace('\x01', '|')}");
// Check session logs
// fix_logs/FIX.4.4-SENDER-GFI.messages.current.log
// Look for reject reasons
grep "35=3" fix_logs/*.log
Task 4: Improve AI Parsing Accuracy
- Add Examples to System Prompt (OpenAIService.cs):
private string BuildSystemPrompt()
{
return @"
...existing prompt...
Additional Examples:
Input: 'new trade type here'
Output: OVML CURNCY MM/DD/YY ...
";
}
- Adjust Temperature:
Temperature = 0.05 // More deterministic (vs. 0.1 default)
- Add Validation Feedback Loop:
var aiResult = await ParseWithAI(input);
var validation = _sanityChecker.ValidateTrade(aiResult);
if (!validation.IsValid)
{
// Send validation errors back to AI for correction
var correctedResult = await ParseWithAI(input, validation.Errors);
}
- Monitor Learned Patterns:
// Check learned_patterns.json
// Remove low-confidence patterns
// Manually curate high-quality patterns
Task 5: Handle New Multi-Leg Structure
Example: Adding "Butterfly" Structure
- Define Structure Type:
// In TradeStructure.cs or constants
public const string STRUCTURE_BUTTERFLY = "11"; // Check GFI spec for actual code
- Add Regex Pattern:
public static (string Pattern, string Name, int Priority) Butterfly()
{
string pattern = @"butterfly\s+(?<ccy>[A-Z]{6})\s+(?<expiry>[^\s]+)\s+(?<strike1>[\d.]+)/(?<strike2>[\d.]+)/(?<strike3>[\d.]+)\s+(?<type>call|put)";
return (pattern, "Butterfly", 90);
}
- Add OVML Generation Logic:
// In TradeParser.cs
if (structureType == "Butterfly")
{
ovml = $"OVML {ccy} {expiry} 3L B,S,B {strike1}{type},{strike2}{type},{strike3}{type} N{not1}M,{not2}M,{not3}M {style}";
}
- Add to OVMLBridge.cs:
// Parse butterfly structure from OVML
if (legs.Count == 3 && directions == "BSB")
{
trade.StructureType = "11"; // Butterfly
}
- Test End-to-End:
var result = await ParseTradeAsync("butterfly EURUSD 17Dec25 1.08/1.09/1.10 call");
Assert.AreEqual("OVML EURUSD 12/17/25 3L B,S,B 1.0800C,1.0900C,1.1000C N10M,20M,10M VA", result.OVML);
Critical Knowledge
OVML Format Specification
Single-Leg Structure:
OVML {CCY} {expiry} {B/S} {strike}{C/P} N{notional}M {VA/EU} [SP{spot}]
Example:
OVML EURNOK 12/17/25 B 9.8500C N25M VA SP10.9518
Multi-Leg Structure:
OVML {CCY} {expiry} {N}L {B/S,...} {strike1}{C/P},{strike2}{C/P},... N{not1}M,{not2}M,... {VA/EU} [SP{spot}]
Example (Risk Reversal):
OVML EURUSD 01/15/26 2L S,B 1.0500P,1.1000C N10M,10M VA SP1.0750
Field Definitions:
- CCY: 6-character currency pair (EURUSD, EURNOK, etc.)
- Expiry: MM/DD/YY format (12/17/25)
- B/S: BUY or SELL
- Strike: 4 decimal places (9.8500)
- C/P: CALL or PUT
- Notional: In millions (25M)
- VA/EU: VANILLA or EUROPEAN (style)
- SP: Spot reference (optional, used for premium calculation)
Multi-Leg Ordering:
- Directions: Comma-separated (B,S,B)
- Strikes: Comma-separated with type (1.05P,1.10C)
- Notionals: Comma-separated (10M,10M)
- CRITICAL: All three lists must have same count
UBS Format Specification
Single-Leg:
{CCY} {strike}{C/P} {CCY1} {notional/10} MIO {dd-MMM-yy} SPOT {spot}
Example:
EURNOK 9.8500C EUR 2.5 MIO 17-Dec-25 SPOT 10.9518
Multi-Leg:
{CCY} {strike1}{C/P} {CCY1} {not1/10}MIO {date}, {CCY} {strike2}{C/P} {not2/10}MIO SPOT {spot}
Example:
EURUSD 1.0500P USD 1.0MIO 15-Jan-26, EURUSD 1.1000C 1.0MIO SPOT 1.0750
Key Differences from OVML:
- Date format: dd-MMM-yy (17-Dec-25) vs MM/DD/YY
- Notional: Divide by 10 (25M → 2.5 MIO)
- Currency: Base currency for notional (EUR for EURNOK)
- Direction: Not explicitly shown (inferred from context)
Strike Ordering Rules
Call Spreads:
- Buy low strike, Sell high strike
- Example: Buy 1.05C, Sell 1.10C
Put Spreads:
- Buy high strike, Sell low strike
- Example: Buy 1.10P, Sell 1.05P
Risk Reversals:
- Sell Put (lower strike), Buy Call (higher strike)
- OR: Buy Put, Sell Call (reverse)
Straddles:
- Same strike for Call and Put
- Example: Buy 1.08C, Buy 1.08P
Strangles:
- Different strikes (Put lower, Call higher)
- Example: Buy 1.05P, Buy 1.10C
Date Handling
Input Formats Supported:
17Dec25(Bloomberg format)17-12-25(dashed format)17 Dec 2025(full year)2025-12-17(ISO format)3M/6M(tenor - calculated from today)1Y/2Y(year tenor)
Output Formats:
- OVML:
MM/DD/YY(12/17/25) - UBS:
dd-MMM-yy(17-Dec-25) - FIX:
yyyyMMdd(20251217)
Tenor Calculations:
- 1M = +30 days
- 3M = +90 days
- 6M = +180 days
- 1Y = +365 days
- Uses FxDateService.cs for business day adjustments
Premium vs Volatility Debate
Recent Commits Show Preference for Premium:
- Tag 6436 (Premium): Primary field for execution logic
- Tag 5678 (Volatility): Secondary, informational
Why Premium is Preferred:
- Direct pricing (no conversion needed)
- Consistent across LPs
- Easier for traders to compare
- Reduces calculation errors
Code Pattern:
// CORRECT - Use Premium for execution
if (quote.Premium > bestOfferPremium)
{
bestOfferQuote = quote;
}
// AVOID - Using volatility requires conversion
// var premium = CalculatePremium(quote.Volatility, spot, strike, expiry);
QuoteID Handling
CRITICAL: Use Exact QuoteID from Quote
BID Quotes: End with -O
OFFER Quotes: End with -T
// WRONG - Don't transform QuoteID
string quoteId = quote.QuoteID.Replace("-O", "-T"); // NO!
// CORRECT - Use as-is
string quoteId = quote.QuoteID; // YES!
Why This Matters:
- GFI uses QuoteID suffixes for internal routing
- Transforming QuoteID causes rejections
- Each side (BID/OFFER) has its own QuoteID
Recent Fix:
// Before (WRONG):
if (selectedSide == "BID")
quoteId = quoteId.Replace("-T", "-O");
// After (CORRECT):
// Use quoteId directly from the selected quote row
Option Type Inference (Ambiguous Trades)
Problem: When traders say "11.75 in 10M" without specifying call/put, what should the system infer?
Industry Standard: Default to OTM (Out-of-the-Money) options
- OTM options are cheaper (lower premium)
- Traders typically buy OTM unless explicitly requesting ITM
- ITM options are more expensive and less common for speculative positions
Inference Logic (OpenAIService.cs line 390-442):
// Only apply when:
// 1. User did NOT specify "call" or "put" in input
// 2. User did NOT provide spot reference (sr:, @, etc.)
// 3. Single-leg trade only (multi-leg strategies are intentional)
if (strike > spot)
→ CALL (OTM - upside speculation)
else if (strike < spot)
→ PUT (OTM - downside protection)
Examples:
Input: "eurnok 11.75 in 10M"
Spot: 11.78
Strike < Spot → Infer PUT
Result: OVML EURNOK ... B 11.7500P N10M VA SP11.78
Input: "eurusd 1.12 in 50M"
Spot: 1.10
Strike > Spot → Infer CALL
Result: OVML EURUSD ... B 1.1200C N50M VA SP1.10
Debug Output:
[AI-TYPE-CHECK] Strike=11.7500, Spot=11.7849, IsCall=True, ShouldBeCall=False
[AI-TYPE-CHECK] ✓ CORRECTED: 11.7500C → 11.7500P
[AI-TYPE-CHECK] Reason: Strike < Spot → Should be P (OTM)
Important Notes:
- If user explicitly says "call" or "put", NO correction is applied
- If user provides spot reference (sr: value), NO correction is applied
- Multi-leg trades are never corrected (strategies are intentional)
- This was a bug until 2025-11-27 - previous code failed to parse strike correctly
Testing & Debugging
Unit Testing Approach
Test Parsing Pipeline:
[Test]
public async Task TestVanillaCallParsing()
{
var parser = new TradeParser(_bloombergService, _openAIService, _sanityChecker);
var result = await parser.ParseTradeAsync("buy 10M EURUSD 3M 1.10 call");
Assert.AreEqual("Regex", result.ParseMethod);
Assert.IsTrue(result.OVML.Contains("EURUSD"));
Assert.IsTrue(result.OVML.Contains("B 1.1000C"));
Assert.IsTrue(result.OVML.Contains("N10M"));
}
[Test]
public async Task TestRiskReversalParsing()
{
var result = await parser.ParseTradeAsync("EURUSD risk reversal sell 1.05 put buy 1.10 call 50M");
Assert.IsTrue(result.OVML.Contains("2L S,B"));
Assert.IsTrue(result.OVML.Contains("1.0500P,1.1000C"));
Assert.AreEqual(0.9, result.Confidence); // High confidence
}
Test Validation Logic:
[Test]
public void TestExpiredDateValidation()
{
string ovml = "OVML EURUSD 01/01/20 B 1.1000C N10M VA"; // Past date
var validation = _sanityChecker.ValidateTrade(ovml, "buy call expired");
Assert.IsFalse(validation.IsValid);
Assert.Contains("expiry date has passed", validation.Errors);
}
Test FIX Message Construction:
[Test]
public void TestQuoteRequestFieldOrder()
{
var trade = new TradeStructure
{
Underlying = "EURUSD",
Expiry = DateTime.Parse("2025-12-17"),
Legs = new List<TradeLeg>
{
new TradeLeg { Direction = "BUY", OptionType = "CALL", Strike = 1.10, NotionalMM = 10 }
}
};
var rawMessage = RawFIXMessageBuilder.BuildQuoteRequest(trade, "QuoteReq123");
// Verify field order: Tag 75 before Tag 5020
int tag75Pos = rawMessage.IndexOf("75=");
int tag5020Pos = rawMessage.IndexOf("5020=");
Assert.IsTrue(tag75Pos < tag5020Pos, "Tag 75 must come before Tag 5020");
// Verify required fields present
Assert.Contains("35=R", rawMessage); // Quote Request
Assert.Contains("55=EURUSD", rawMessage);
Assert.Contains("6120=1", rawMessage); // 1 leg
}
Debugging Strategies
1. Console Logging:
// Program.cs allocates console for debug output
[STAThread]
static void Main()
{
AllocConsole(); // Creates console window
Application.Run(new MainForm());
}
// Use throughout codebase
Console.WriteLine($"[TRACE] {DateTime.Now:HH:mm:ss.fff} | {eventName} | {details}");
2. FIX Session Logs:
# Location: fix_logs/
FIX.4.4-SENDER-GFI.messages.current.log # Message history
FIX.4.4-SENDER-GFI.event.current.log # Session events
# View recent messages
tail -f fix_logs/FIX.4.4-SENDER-GFI.messages.current.log
# Search for rejections
grep "35=3" fix_logs/*.log # Reject messages
grep "35=9" fix_logs/*.log # Cancel Reject
3. Message Tracing:
// In GFIFIXApplication.cs
public override void OnMessage(QuickFix.FIX44.Quote quote, SessionID sessionID)
{
Console.WriteLine($"[FIX IN] Quote received");
Console.WriteLine($" QuoteID: {quote.QuoteID.getValue()}");
Console.WriteLine($" BidPremium: {quote.GetField(6436)}");
Console.WriteLine($" OfferPremium: {quote.GetField(6436)}");
// ... rest of processing
}
4. UI Debug Panel:
// MainForm.cs has debug log panel
private void AppendLog(string message)
{
txtDebugLog.AppendText($"[{DateTime.Now:HH:mm:ss}] {message}\r\n");
}
5. Network Traffic Analysis:
# Use Wireshark to capture FIX messages
# Filter: tcp.port == 9443
# Analyze field order and values
Common Issues & Solutions
Issue 1: Bloomberg API Not Connecting
- Symptom: "Bloomberg not connected" status
- Check: Is Bloomberg Terminal running? (
bplus.exeprocess) - Check: Is Desktop API enabled in Terminal? (WAPI <GO>)
- Fix: Restart Bloomberg Terminal, verify WAPI settings
Issue 2: FIX Session Not Logging In
- Symptom: Session stuck in "Connecting" state
- Check: Is SSLTunnelProxy running? (localhost:9443)
- Check: Are credentials correct in
quickfix.cfg? - Fix: Verify proxy settings, check GFI credentials
Issue 3: Quote Requests Rejected
- Symptom: Immediate reject after quote request
- Check: Field order in
RawFIXMessageBuilder.cs - Check: Required fields present (Tag 75, 5020, 6120, etc.)
- Debug: Compare with accepted messages in logs
- Fix: Adjust field order to match specification
Issue 4: Execution Orders Rejected
- Symptom: Order rejected with "Invalid QuoteID"
- Check: Using exact QuoteID from quote? (don't transform)
- Check: Quote still valid? (Tag 62 ValidUntilTime)
- Fix: Use QuoteID as-is, execute before expiry
Issue 5: AI Parsing Incorrect
- Symptom: AI returns wrong OVML
- Check: Validation logic catching errors?
- Check: System prompt comprehensive?
- Debug: Log AI response before validation
- Fix: Add examples to prompt, improve validation
Issue 6: Wrong Option Type When Strike Near Spot (FIXED 2025-11-27)
- Symptom: Input "11.75 in 10M" with spot=11.78 returns CALL (ITM) instead of PUT (OTM)
- Root Cause: Parsing bug in OpenAIService.cs line 398 - tried to parse "11.7500C" as double, failed due to 'C' suffix
- Expected Behavior: Strike < Spot → Should infer PUT (OTM option)
- Fix Applied: Extract numeric strike using regex before parsing, added debug logging
- Check: Look for
[AI-TYPE-CHECK]console logs showing strike/spot comparison and correction - Note: Correction only applies when user didn't specify "call" or "put" AND no spot reference provided
Git Workflow
Branch Naming Convention
# Feature branches (created by Claude)
claude/feature-name-sessionid-requestid
# Current branch
claude/claude-md-mihdmpmblb74y627-01A1GqpFBEwLwjcnBWdmsPfv
Commit Message Standards
# Format: <type>: <brief description>
# Types:
feat: # New feature
fix: # Bug fix
refactor: # Code refactoring
docs: # Documentation changes
test: # Test additions/changes
chore: # Build, config, dependencies
# Examples:
feat: Add butterfly spread pattern support
fix: Correct QuoteID handling for BID/OFFER quotes
refactor: Extract FIX field ordering logic
docs: Update CLAUDE.md with FIX integration notes
Push Workflow
# 1. Verify you're on correct branch
git branch
# Should show: claude/...
# 2. Stage changes
git add -A
# 3. Commit with descriptive message
git commit -m "feat: Add comprehensive CLAUDE.md documentation"
# 4. Push to remote (with retry logic for network issues)
git push -u origin claude/claude-md-mihdmpmblb74y627-01A1GqpFBEwLwjcnBWdmsPfv
# Retry up to 4 times with exponential backoff (2s, 4s, 8s, 16s)
Recent Development History
Last 5 Commits (Most Recent First):
-
db4060e: Revert "Change execution and highlighting logic to use VOLS instead of PREMIUMS"
- Impact: Reverted to premium-based execution
- Reason: Volatility-based logic caused execution issues
-
12aef10: Change execution and highlighting logic to use VOLS instead of PREMIUMS
- Impact: Attempted vol-based execution (later reverted)
- Reason: Experimentation with pricing method
-
d22ae9e: Add spot reference logging to investigate premium differences
- Impact: Enhanced debugging for premium calculations
- Files: GFIQuoteDialog.cs
-
8f04287: Add minimal premium logging to verify Tag 6436 values and conversion
- Impact: Tag 6436 investigation
- Files: GFIFIXApplication.cs
-
1dfdbe7: Remove premium debug logging after issue resolution
- Impact: Cleanup after successful debug
- Files: GFIFIXApplication.cs
Key Takeaway: Recent focus on premium pricing accuracy and execution logic. Prefer premium (Tag 6436) over volatility (Tag 5678) for execution.
Additional Resources
External Documentation
- GFI FIX Specification:
/Documentation/BGC__GFI_FIX_Specification_for_FX_v1_4_4.pdf - Bloomberg API: Bloomberg Terminal → WAPI <GO>
- QuickFix Documentation: https://www.quickfixengine.org/
- OpenAI API: https://platform.openai.com/docs/
Configuration Files
- quickfix.cfg: FIX session configuration (credentials, connection)
- App.config: OpenAI API key, application settings
- FIX44.xml: FIX 4.4 data dictionary
Persistence Locations
- Trade History:
%AppData%/FXOAiTranslator/trades.json - Learned Patterns:
%AppData%/FXOAiTranslator/learned_patterns.json - FIX Logs:
fix_logs/directory - FIX Store:
fix_store/directory
Key Constants
// Currency pairs (24 supported)
"EURUSD", "USDJPY", "GBPUSD", "AUDUSD", "USDCAD", "USDCHF",
"NZDUSD", "EURGBP", "EURJPY", "GBPJPY", "EURCHF", "AUDJPY",
"EURAUD", "EURNOK", "EURSEK", "USDNOK", "USDSEK", "USDTRY",
"USDMXN", "USDZAR", "EURCAD", "AUDNZD", "NOKSEK", "EURTRY"
// Structure types (GFI FIX)
1 = Vanilla
5 = Risk Reversal
8 = Call Spread
9 = Put Spread
10 = Seagull
// Parse methods (UI color coding)
"Regex" = Green
"Learned" = Yellow
"AI" = Blue
"Warning" = Orange
"Error" = Red
// Confidence levels
0.9 = Perfect (no issues)
0.75 = Good (minor warnings)
0.5 = Acceptable (some concerns)
0.1 = Failed (validation errors)
Appendix: Quick Reference
Command Cheat Sheet
# Build solution
dotnet build FXOAiTranslator.sln
# Run main application
dotnet run --project FXOAiTranslator.csproj
# Run tests (if test project exists)
dotnet test
# Clean build artifacts
dotnet clean
# View git history
git log --oneline -10
# Check git status
git status
# View FIX logs
tail -f fix_logs/FIX.4.4-SENDER-GFI.messages.current.log
Code Snippets
Parse Trade:
var result = await _tradeParser.ParseTradeAsync("buy 10M EURUSD 3M 1.10 call");
Console.WriteLine($"OVML: {result.OVML}");
Console.WriteLine($"UBS: {result.UBSFormat}");
Console.WriteLine($"Method: {result.ParseMethod}");
Console.WriteLine($"Confidence: {result.Confidence}");
Send to Bloomberg:
if (_bloombergService.IsBloombergConnected())
{
await _bloombergService.SendOVMLAsync(ovml);
}
Get Quote from GFI:
var trade = OVMLBridge.ConvertToTradeStructure(ovml);
_fixSession.SendQuoteRequest(trade);
// Wait for OnMessage(Quote) callback
Execute Trade:
_fixSession.SendNewOrderMultileg(trade, quoteId, selectedSide);
// Wait for OnMessage(ExecutionReport) callback
Change Log
| Date | Version | Changes |
|---|---|---|
| 2025-11-27 | 1.0 | Initial comprehensive CLAUDE.md creation |
Contact & Support
For questions about this codebase, refer to:
- Recent git history:
git log --oneline -20 - Code comments in key files (MainForm.cs, TradeParser.cs)
- GFI FIX specification PDF
- Bloomberg WAPI documentation
End of CLAUDE.md
What's inside
11 sections covering architecture, 10 key components, 5 development workflows, coding conventions, integration points, and 5 common tasks with step-by-step instructions.
Change this for your project
- Replace
YOUR_SENDER_IDinquickfix.cfgwith your own SenderCompID - Replace
sk-...inApp.configwith your own OpenAI API key - Replace
GFI_TARGET_IDinquickfix.cfgwith your GFI TargetCompID - Replace
localhost:9443inquickfix.cfgwith your SSLTunnelProxy host and port
Where it goes
Save as CLAUDE.md in your repository root. Claude Code reads it automatically at the start of every session.
Worth borrowing
- Three-tier parsing strategy (Regex → Learned Patterns → AI Fallback) with caching and pattern learning to reduce API calls
- Raw FIX message builder that preserves exact field ordering required by GFI, bypassing QuickFix's default tag-sorting
- Color-coded UI feedback (green/yellow/blue/orange/red) to indicate which parsing method succeeded
Related Documents
Code indexing for AI agents: summarization strategies and evaluation systems
Synthesises 2024-2025 research on code indexing for AI agents, covering summarisation strategies, hybrid retrieval architectures, and evaluation benchmarks.
Claude AI Git Workflow Integration
Recommends using the git-ai-commit CLI tool for AI-generated commit messages instead of manual ones.
Missing Business Agents Research — FLUXION 2026
Identifies 12 missing business operations agents for an indie software company and ranks them by impact and effort with €0 implementation plans.
角色:金牌面试者
Prompts Claude to act as a resume consultant, collecting user info and generating a polished A4-format React resume component with STAR-format experience.