Index: src/register/ledger-core/split-register-model-save.c
===================================================================
--- src/register/ledger-core/split-register-model-save.c	(revision 18399)
+++ src/register/ledger-core/split-register-model-save.c	(working copy)
@@ -386,9 +386,66 @@
 {
   Account *acc;
   gnc_numeric new_amount, convrate, amtconv, value;
+  gnc_commodity *curr, *reg_com, *xfer_com;
+  Account *xfer_acc;
 
   new_amount = gnc_split_register_debcred_cell_value (reg);
+  acc = gnc_split_register_get_default_account (reg);
+  
+  xfer_acc = xaccSplitGetAccount (sd->split);
+  xfer_com = xaccAccountGetCommodity (xfer_acc);
+  reg_com = xaccAccountGetCommodity (acc);  
+  curr = xaccTransGetCurrency (sd->trans);
+  
+  /* First, compute the conversion rate to convert the value to the
+    * amount.
+    */
+  amtconv = convrate = gnc_split_register_get_rate_cell (reg, RATE_CELL);
+  if (gnc_split_register_needs_conv_rate (reg, sd->trans, acc)) {
+    
+    /* If we are in an expanded register and the xfer_acc->comm !=
+    * reg_acc->comm then we need to compute the convrate here.
+    * Otherwise, we _can_ use the rate_cell!
+    */
+    if (sd->reg_expanded && ! gnc_commodity_equal (reg_com, xfer_com))
+      amtconv = xaccTransGetAccountConvRate(sd->trans, acc);
+  }
+  
+  if (xaccTransUseTradingAccounts (sd->trans)) {
+    /* Using currency accounts, the amount is probably really the
+       amount and not the value. */
+    gboolean is_amount;
+    if (reg->type == STOCK_REGISTER || 
+        reg->type == CURRENCY_REGISTER ||
+        reg->type == PORTFOLIO_LEDGER) {
+      if (xaccAccountIsPriced(xfer_acc) || 
+          !gnc_commodity_is_iso(xaccAccountGetCommodity(xfer_acc))) 
+        is_amount = FALSE;
+      else
+        is_amount = TRUE;
+    }
+    else {
+      is_amount = TRUE;
+    }
 
+    if (is_amount) {
+      xaccSplitSetAmount(sd->split, new_amount);
+      if (gnc_split_register_split_needs_amount (reg, sd->split)) {
+        value = gnc_numeric_div(new_amount, amtconv,
+                                gnc_commodity_get_fraction(curr),
+                                GNC_RND_ROUND);
+        xaccSplitSetValue(sd->split, value);
+      }
+      else
+        xaccSplitSetValue(sd->split, new_amount);
+    }
+    else {
+      xaccSplitSetValue(sd->split, new_amount);
+    }
+    
+    return;
+  }
+        
   /* How to interpret new_amount depends on our view of this
    * transaction.  If we're sitting in an account with the same
    * commodity as the transaction, then we can set the Value and then
@@ -397,34 +454,12 @@
    * 'value' by dividing by the convrate in order to set the value.
    */
 
-  /* First, compute the conversion rate to convert the value to the
-   * amount.
-   */
-  convrate = gnc_split_register_get_rate_cell (reg, RATE_CELL);
-
   /* Now compute/set the split value.  Amount is in the register
    * currency but we need to convert to the txn currency.
    */
-  acc = gnc_split_register_get_default_account (reg);
   if (gnc_split_register_needs_conv_rate (reg, sd->trans, acc)) {
-    gnc_commodity *curr, *reg_com, *xfer_com;
-    Account *xfer_acc;
 
-    xfer_acc = xaccSplitGetAccount (sd->split);
-    xfer_com = xaccAccountGetCommodity (xfer_acc);
-    reg_com = xaccAccountGetCommodity (acc);
-
-    /* If we are in an expanded register and the xfer_acc->comm !=
-     * reg_acc->comm then we need to compute the convrate here.
-     * Otherwise, we _can_ use the rate_cell!
-     */
-    if (sd->reg_expanded && ! gnc_commodity_equal (reg_com, xfer_com))
-      amtconv = xaccTransGetAccountConvRate(sd->trans, acc);
-    else
-      amtconv = convrate;
-
     /* convert the amount to the Value ... */
-    curr = xaccTransGetCurrency (sd->trans);
     value = gnc_numeric_div (new_amount, amtconv,
 			     gnc_commodity_get_fraction (curr),
 			     GNC_RND_ROUND);
Index: src/register/ledger-core/gnc-ledger-display.c
===================================================================
--- src/register/ledger-core/gnc-ledger-display.c	(revision 18399)
+++ src/register/ledger-core/gnc-ledger-display.c	(working copy)
@@ -281,6 +281,9 @@
 
       case ACCT_TYPE_CURRENCY:
         return CURRENCY_REGISTER;
+        
+      case ACCT_TYPE_TRADING:
+        return TRADING_REGISTER;
 
       default:
         PERR ("unknown account type %d\n", account_type);
@@ -327,6 +330,7 @@
       break;
 
     case ACCT_TYPE_EQUITY:
+    case ACCT_TYPE_TRADING:
       reg_type = GENERAL_LEDGER;
       break;
 
Index: src/register/ledger-core/split-register-model.c
===================================================================
--- src/register/ledger-core/split-register-model.c	(revision 18399)
+++ src/register/ledger-core/split-register-model.c	(working copy)
@@ -163,6 +163,11 @@
   if (!account)
     return TRUE;
 
+  if (xaccTransUseTradingAccounts (xaccSplitGetParent (split))) {
+    if (!gnc_commodity_is_iso(xaccAccountGetCommodity(account)))
+      return TRUE;
+  }
+  
   return xaccAccountIsPriced(account);
 }
 
@@ -680,7 +685,7 @@
     trans = gnc_split_register_get_trans (reg, virt_loc.vcell_loc);
 
     if (trans)
-      *hatching = !gnc_numeric_zero_p (xaccTransGetImbalance (trans));
+      *hatching = !xaccTransIsBalanced (trans);
     else
       *hatching = FALSE;
   }
@@ -1456,6 +1461,7 @@
   case INCOME_REGISTER:
   case EXPENSE_REGISTER:
   case EQUITY_REGISTER:
+  case TRADING_REGISTER:
   case GENERAL_LEDGER:
   case INCOME_LEDGER:
   case PORTFOLIO_LEDGER:
@@ -1521,10 +1527,43 @@
     gnc_numeric imbalance;
     Account *acc;
 
-    imbalance = xaccTransGetImbalance (trans);
-
+    imbalance = xaccTransGetImbalanceValue (trans);
+ 
     if (gnc_numeric_zero_p (imbalance))
       return NULL;
+   
+    if (xaccTransUseTradingAccounts (trans)) {
+      MonetaryList *imbal_list;
+      gnc_monetary *imbal_mon;
+      imbal_list = xaccTransGetImbalance (trans);
+      
+      if (!imbal_list) {
+        /* No commodity imbalance, there shouldn't be a value imablance. */
+        return NULL;
+      }
+  
+      if (imbal_list->next) {
+        /* Multiple currency imbalance. */
+        gnc_monetary_list_free(imbal_list);
+        return NULL;
+      }
+      
+      imbal_mon = imbal_list->data;
+      if (!gnc_commodity_equal(gnc_monetary_commodity(*imbal_mon), currency)) {
+        /* Imbalance is in wrong currency */
+        gnc_monetary_list_free(imbal_list);
+        return NULL;
+      }
+      
+      if (!gnc_numeric_equal (gnc_monetary_value(*imbal_mon), imbalance)) {
+        /* Value and commodity imbalances differ */
+        gnc_monetary_list_free(imbal_list);
+        return NULL;
+      } 
+      
+      /* Done with the imbalance list */
+      gnc_monetary_list_free(imbal_list);
+    }
 
     imbalance = gnc_numeric_neg (imbalance);
 
@@ -1556,35 +1595,76 @@
 
   {
     gnc_numeric amount;
+    gnc_commodity *split_commodity;
     GNCPrintAmountInfo print_info;
+    Account *account;
+    gnc_commodity * commodity;
+          
+    account = gnc_split_register_get_default_account (reg);
+    commodity = xaccAccountGetCommodity (account);
+    split_commodity = xaccAccountGetCommodity(xaccSplitGetAccount(split));
 
-    /* If this account is not a stock/mutual/currency account, and
-     * currency != the account commodity, then use the SplitAmount
-     * instead of the SplitValue.
-     */
-    switch (reg->type) {
-    case STOCK_REGISTER:
-    case CURRENCY_REGISTER:
-      amount = xaccSplitGetValue (split);
-      print_info = gnc_commodity_print_info (currency, FALSE);
-      break;
-
-    default:
-      {
-	Account *account;
-	gnc_commodity * commodity;
-
-	account = gnc_split_register_get_default_account (reg);
-	commodity = xaccAccountGetCommodity (account);
-
-	if (commodity && !gnc_commodity_equal (commodity, currency))
-	  /* Convert this to the "local" value */
-	  amount = xaccSplitConvertAmount(split, account);
-	else
-	  amount = xaccSplitGetValue (split);
-	print_info = gnc_account_print_info (account, FALSE);
+    if (xaccTransUseTradingAccounts (trans)) {
+      gboolean use_symbol, is_current;
+      is_current = virt_cell_loc_equal (reg->table->current_cursor_loc.vcell_loc,
+                                        virt_loc.vcell_loc);
+      
+      if (reg->type == STOCK_REGISTER || 
+          reg->type == CURRENCY_REGISTER ||
+          reg->type == PORTFOLIO_LEDGER) {
+        gnc_commodity *amount_commodity;
+        /* security register.  If this split has price and shares columns,
+           use the value, otherwise use the amount.  */
+        if (gnc_split_register_use_security_cells(reg, virt_loc)) {
+          amount = xaccSplitGetValue(split);
+          amount_commodity = currency;
+        }
+        else {
+          amount = xaccSplitGetAmount(split);
+          amount_commodity = split_commodity;
+        }
+        /* Show the currency if it is not the default currency */
+        if (is_current ||
+            gnc_commodity_equiv(amount_commodity, gnc_default_currency())) 
+          use_symbol = FALSE;
+        else
+          use_symbol = TRUE;
+        print_info = gnc_commodity_print_info(amount_commodity, use_symbol);
       }
+      else {
+        /* non-security register, always use the split amount. */
+        amount = xaccSplitGetAmount(split);
+        if (is_current ||
+            gnc_commodity_equiv(split_commodity, commodity)) 
+          use_symbol = FALSE;
+        else
+          use_symbol = TRUE;
+        print_info = gnc_commodity_print_info(split_commodity, use_symbol);
+      }
     }
+    else {
+      /* If this account is not a stock/mutual/currency account, and
+      * currency != the account commodity, then use the SplitAmount
+      * instead of the SplitValue.
+      */
+      switch (reg->type) {
+        case STOCK_REGISTER:
+        case CURRENCY_REGISTER:
+          amount = xaccSplitGetValue (split);
+          print_info = gnc_commodity_print_info (currency, FALSE);
+          break;
+          
+        default:
+        {
+          if (commodity && !gnc_commodity_equal (commodity, currency))
+            /* Convert this to the "local" value */
+            amount = xaccSplitConvertAmount(split, account);
+          else
+            amount = xaccSplitGetValue (split);
+          print_info = gnc_account_print_info (account, FALSE);
+        }
+      }
+    }
 
     if (gnc_numeric_zero_p (amount))
       return NULL;
Index: src/register/ledger-core/split-register.c
===================================================================
--- src/register/ledger-core/split-register.c	(revision 18399)
+++ src/register/ledger-core/split-register.c	(working copy)
@@ -1782,6 +1782,16 @@
   if (!price_changed && !amount_changed && !shares_changed)
     return TRUE;
 
+  /* If we are using commodity trading accounts then the value may
+     not really be the value.  Punt if so. */
+  if (xaccTransUseTradingAccounts (xaccSplitGetParent (split))) {
+    gnc_commodity *acc_commodity;
+    acc_commodity = xaccAccountGetCommodity (account);
+    if (! (xaccAccountIsPriced (account) ||
+           !gnc_commodity_is_iso (acc_commodity)))
+      return TRUE;
+  }
+    
   if (shares_changed)
   {
     cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
@@ -2053,6 +2063,8 @@
       return ACCT_TYPE_STOCK;
     case CURRENCY_REGISTER:
       return ACCT_TYPE_CURRENCY;
+    case TRADING_REGISTER:
+      return ACCT_TYPE_TRADING;
     case GENERAL_LEDGER:  
       return ACCT_TYPE_NONE;
     case EQUITY_REGISTER:
@@ -2253,6 +2265,7 @@
       gnc_combo_cell_add_menu_item (cell, _("Paycheck"));
       break;
     case EXPENSE_REGISTER:
+    case TRADING_REGISTER:
       gnc_combo_cell_add_menu_item (cell, _("Increase"));
       gnc_combo_cell_add_menu_item (cell, _("Decrease"));
       gnc_combo_cell_add_menu_item (cell, _("Buy"));
Index: src/register/ledger-core/split-register.h
===================================================================
--- src/register/ledger-core/split-register.h	(revision 18399)
+++ src/register/ledger-core/split-register.h	(working copy)
@@ -163,6 +163,7 @@
   CURRENCY_REGISTER,
   RECEIVABLE_REGISTER,
   PAYABLE_REGISTER,
+  TRADING_REGISTER,
   NUM_SINGLE_REGISTER_TYPES,
 
   GENERAL_LEDGER = NUM_SINGLE_REGISTER_TYPES,
Index: src/register/ledger-core/split-register-layout.c
===================================================================
--- src/register/ledger-core/split-register-layout.c	(revision 18399)
+++ src/register/ledger-core/split-register-layout.c	(working copy)
@@ -92,6 +92,7 @@
     case INCOME_REGISTER:
     case EXPENSE_REGISTER:
     case EQUITY_REGISTER:
+    case TRADING_REGISTER:
       {
         curs = gnc_table_layout_get_cursor (layout,
                                             CURSOR_SINGLE_LEDGER);
@@ -456,6 +457,7 @@
     case INCOME_REGISTER:
     case EXPENSE_REGISTER:
     case EQUITY_REGISTER:
+    case TRADING_REGISTER:
       num_cols = 9;
       break;
 
Index: src/register/ledger-core/split-register-control.c
===================================================================
--- src/register/ledger-core/split-register-control.c	(revision 18399)
+++ src/register/ledger-core/split-register-control.c	(working copy)
@@ -59,12 +59,40 @@
     Split *split;
     Split *other_split;
     gboolean two_accounts;
+    gboolean multi_currency;
 
 
-    imbalance = xaccTransGetImbalance (trans);
-    if (gnc_numeric_zero_p (imbalance))
-        return FALSE;
-  
+    if (xaccTransIsBalanced (trans))
+      return FALSE;
+    
+    if (xaccTransUseTradingAccounts (trans)) {
+      MonetaryList *imbal_list;
+      gnc_monetary *imbal_mon;
+      imbal_list = xaccTransGetImbalance (trans);
+      
+      /* See if the imbalance is only in the transaction's currency */
+      if (!imbal_list)
+        /* Value imbalance, but not commodity imbalance.  This shouldn't
+           be something that scrubbing can cause to happen.  Perhaps someone
+           entered invalid splits.  */
+        multi_currency = TRUE;
+      else {
+        imbal_mon = imbal_list->data;
+        if (!imbal_list->next && 
+            gnc_commodity_equiv(gnc_monetary_commodity(*imbal_mon),
+                                xaccTransGetCurrency(trans))) 
+          multi_currency = FALSE;
+        else 
+          multi_currency = TRUE;
+      }
+      
+      /* We're done with the imbalance list, the real work will be done
+         by xaccTransScrubImbalance which will get it again. */
+      gnc_monetary_list_free(imbal_list);
+    }
+    else 
+      multi_currency = FALSE;
+    
     split = xaccTransGetSplit (trans, 0);
     other_split = xaccSplitGetOtherSplit (split);
   
@@ -75,7 +103,7 @@
        if (split) other_split = xaccSplitGetOtherSplit (split);
        else split = xaccTransGetSplit (trans, 0);
     }
-    if (other_split == NULL)
+    if (other_split == NULL || multi_currency)
     {
       two_accounts = FALSE;
       other_account = NULL;
@@ -107,7 +135,7 @@
     radio_list = g_list_append (radio_list,
                                 _("Let GnuCash _add an adjusting split"));
 
-    if (reg->type < NUM_SINGLE_REGISTER_TYPES)
+    if (reg->type < NUM_SINGLE_REGISTER_TYPES && !multi_currency)
     {
       radio_list = g_list_append (radio_list,
                                   _("Adjust current account _split total"));
Index: src/import-export/import-main-matcher.c
===================================================================
--- src/import-export/import-main-matcher.c	(revision 18399)
+++ src/import-export/import-main-matcher.c	(working copy)
@@ -605,10 +605,12 @@
 	}
       else
 	{
+          /* Assume that importers won't create transactions in two or more
+             currencies so we can use xaccTransGetImbalanceValue */
 	  imbalance = 
 	    g_strdup 
 	    (xaccPrintAmount
-	     (gnc_numeric_neg(xaccTransGetImbalance
+	     (gnc_numeric_neg(xaccTransGetImbalanceValue
 			      (gnc_import_TransInfo_get_trans(info) )), 
 	      gnc_commodity_print_info 
 	      (xaccTransGetCurrency(gnc_import_TransInfo_get_trans (info)),
Index: src/import-export/import-backend.c
===================================================================
--- src/import-export/import-backend.c	(revision 18399)
+++ src/import-export/import-backend.c	(working copy)
@@ -122,7 +122,10 @@
 gnc_import_TransInfo_is_balanced (const GNCImportTransInfo *info)
 {
  g_assert (info);
- if(gnc_numeric_zero_p(xaccTransGetImbalance(gnc_import_TransInfo_get_trans(info))))
+ /* Assume that the importer won't create a transaction that involves two or more
+    currencies and no non-currency commodity.  In that case can use the simpler
+    value imbalance check. */
+ if(gnc_numeric_zero_p(xaccTransGetImbalanceValue(gnc_import_TransInfo_get_trans(info))))
    {
      return TRUE;
    }
@@ -860,9 +863,11 @@
 	       (gnc_import_TransInfo_get_trans (trans_info)));*/
 	    {
 	      /* This is a quick workaround for the bug described in
-		 http://gnucash.org/pipermail/gnucash-devel/2003-August/009982.html  */
+		 http://gnucash.org/pipermail/gnucash-devel/2003-August/009982.html
+                 Assume that importers won't create transactions involving two or more
+                 currencies so we can use xaccTransGetImbalanceValue. */
 	      gnc_numeric v = 
-		gnc_numeric_neg (xaccTransGetImbalance 
+		gnc_numeric_neg (xaccTransGetImbalanceValue 
 				 (gnc_import_TransInfo_get_trans (trans_info)));
 	      xaccSplitSetValue (split, v);
 	      xaccSplitSetAmount (split, v);
Index: src/import-export/import-match-picker.c
===================================================================
--- src/import-export/import-match-picker.c	(revision 18399)
+++ src/import-export/import-match-picker.c	(working copy)
@@ -151,7 +151,10 @@
   gtk_list_store_set(store, &iter, DOWNLOADED_COL_MEMO, ro_text, -1);
 
   /*Imbalance*/
-  ro_text = xaccPrintAmount(xaccTransGetImbalance(trans), 
+ /* Assume that the importer won't create a transaction that involves two or more
+    currencies and no non-currency commodity.  In that case can use the simpler
+    value imbalance check. */
+  ro_text = xaccPrintAmount(xaccTransGetImbalanceValue(trans), 
 			    gnc_default_print_info(TRUE));
   gtk_list_store_set(store, &iter, DOWNLOADED_COL_BALANCED, ro_text, -1);
 
Index: src/report/standard-reports/trial-balance.scm
===================================================================
--- src/report/standard-reports/trial-balance.scm	(revision 18399)
+++ src/report/standard-reports/trial-balance.scm	(working copy)
@@ -184,7 +184,8 @@
                ACCT-TYPE-ASSET ACCT-TYPE-LIABILITY
                ACCT-TYPE-STOCK ACCT-TYPE-MUTUAL ACCT-TYPE-CURRENCY
                ACCT-TYPE-PAYABLE ACCT-TYPE-RECEIVABLE
-               ACCT-TYPE-EQUITY ACCT-TYPE-INCOME ACCT-TYPE-EXPENSE)
+               ACCT-TYPE-EQUITY ACCT-TYPE-INCOME ACCT-TYPE-EXPENSE
+               ACCT-TYPE-TRADING)
          (gnc-account-get-descendants-sorted (gnc-get-current-root-account))))
       #f #t))
     (gnc:options-add-account-levels!
Index: src/report/standard-reports/advanced-portfolio.scm
===================================================================
--- src/report/standard-reports/advanced-portfolio.scm	(revision 18399)
+++ src/report/standard-reports/advanced-portfolio.scm	(working copy)
@@ -411,6 +411,7 @@
 			(lambda (s)
 			(if (and (not (or (split-account-type? s ACCT-TYPE-EXPENSE)
 					  (split-account-type? s ACCT-TYPE-INCOME)
+					  (split-account-type? s ACCT-TYPE-TRADING)
 					  (split-account-type? s ACCT-TYPE-ROOT)))
 				 (not (same-account? current (xaccSplitGetAccount s))))
 			    (begin
Index: src/report/standard-reports/equity-statement.scm
===================================================================
--- src/report/standard-reports/equity-statement.scm	(revision 18399)
+++ src/report/standard-reports/equity-statement.scm	(working copy)
@@ -133,7 +133,8 @@
                ACCT-TYPE-ASSET ACCT-TYPE-LIABILITY
                ACCT-TYPE-STOCK ACCT-TYPE-MUTUAL ACCT-TYPE-CURRENCY
                ACCT-TYPE-PAYABLE ACCT-TYPE-RECEIVABLE
-               ACCT-TYPE-EQUITY ACCT-TYPE-INCOME ACCT-TYPE-EXPENSE)
+               ACCT-TYPE-EQUITY ACCT-TYPE-INCOME ACCT-TYPE-EXPENSE
+               ACCT-TYPE-TRADING)
          (gnc-account-get-descendants-sorted (gnc-get-current-root-account))))
       #f #t))
     
@@ -245,7 +246,8 @@
           (assoc-ref split-up-accounts ACCT-TYPE-LIABILITY))
          (income-expense-accounts
           (append (assoc-ref split-up-accounts ACCT-TYPE-INCOME)
-                  (assoc-ref split-up-accounts ACCT-TYPE-EXPENSE)))
+                  (assoc-ref split-up-accounts ACCT-TYPE-EXPENSE)
+                  (assoc-ref split-up-accounts ACCT-TYPE-TRADING)))
          (equity-accounts
           (assoc-ref split-up-accounts ACCT-TYPE-EQUITY))
 
Index: src/report/standard-reports/transaction.scm
===================================================================
--- src/report/standard-reports/transaction.scm	(revision 18399)
+++ src/report/standard-reports/transaction.scm	(working copy)
@@ -612,7 +612,8 @@
              ACCT-TYPE-ASSET ACCT-TYPE-LIABILITY
              ACCT-TYPE-STOCK ACCT-TYPE-MUTUAL ACCT-TYPE-CURRENCY
              ACCT-TYPE-PAYABLE ACCT-TYPE-RECEIVABLE
-             ACCT-TYPE-EQUITY ACCT-TYPE-INCOME ACCT-TYPE-EXPENSE)
+             ACCT-TYPE-EQUITY ACCT-TYPE-INCOME ACCT-TYPE-EXPENSE
+             ACCT-TYPE-TRADING)
        (gnc-account-get-descendants-sorted (gnc-get-current-root-account))))
     #f #t))
 
Index: src/report/standard-reports/balance-sheet.scm
===================================================================
--- src/report/standard-reports/balance-sheet.scm	(revision 18399)
+++ src/report/standard-reports/balance-sheet.scm	(working copy)
@@ -189,7 +189,8 @@
                ACCT-TYPE-ASSET ACCT-TYPE-LIABILITY
                ACCT-TYPE-STOCK ACCT-TYPE-MUTUAL ACCT-TYPE-CURRENCY
                ACCT-TYPE-PAYABLE ACCT-TYPE-RECEIVABLE
-               ACCT-TYPE-EQUITY ACCT-TYPE-INCOME ACCT-TYPE-EXPENSE)
+               ACCT-TYPE-EQUITY ACCT-TYPE-INCOME ACCT-TYPE-EXPENSE
+               ACCT-TYPE-TRADING)
 	 (gnc-account-get-descendants-sorted (gnc-get-current-root-account))))
       #f #t))
     (gnc:options-add-account-levels!
@@ -358,6 +359,8 @@
                   (assoc-ref split-up-accounts ACCT-TYPE-EXPENSE)))
          (equity-accounts
           (assoc-ref split-up-accounts ACCT-TYPE-EQUITY))
+         (trading-accounts
+          (assoc-ref split-up-accounts ACCT-TYPE-TRADING))
 	 
          (doc (gnc:make-html-document))
 	 ;; this can occasionally put extra (blank) columns in our
@@ -441,6 +444,8 @@
                (equity-balance #f)
 	       (neg-retained-earnings #f) ;; credit, income - expenses, < 0
 	       (retained-earnings #f)
+	       (neg-trading-balance #f)
+	       (trading-balance #f)
                (unrealized-gain-collector #f)
                (total-equity-balance #f)
                (liability-plus-equity #f)
@@ -501,6 +506,13 @@
 	  (retained-earnings 'minusmerge
 			  neg-retained-earnings
 			  #f)
+	  (set! neg-trading-balance
+	        (gnc:accountlist-get-comm-balance-at-date
+	         trading-accounts date-tp))
+	  (set! trading-balance (gnc:make-commodity-collector))
+	  (trading-balance 'minusmerge
+	                   neg-trading-balance
+	                   #f)
 	  (gnc:report-percent-done 14)
 	  ;; sum any unrealized gains
 	  ;; 
@@ -537,6 +549,9 @@
 	  (total-equity-balance 'merge
 				unrealized-gain-collector
 				#f)
+	  (total-equity-balance 'merge
+	                        trading-balance
+	                        #f)
 	  (gnc:report-percent-done 18)
 	  (set! liability-plus-equity (gnc:make-commodity-collector))
 	  (liability-plus-equity 'merge
@@ -650,6 +665,12 @@
 				  (_ "Retained Losses")
 				  retained-earnings))
 	  (and (not (gnc-commodity-collector-allzero?
+	             trading-balance))
+	       (add-subtotal-line right-table
+	                          (_ "Trading Gains")
+	                          (_ "Trading Losses")
+	                          trading-balance))
+	  (and (not (gnc-commodity-collector-allzero?
 		     unrealized-gain-collector))
 	       (add-subtotal-line right-table
 				  (_ "Unrealized Gains")
Index: src/report/report-system/report-utilities.scm
===================================================================
--- src/report/report-system/report-utilities.scm	(revision 18399)
+++ src/report/report-system/report-utilities.scm	(working copy)
@@ -96,7 +96,8 @@
                     ACCT-TYPE-CREDITLINE))
 	(cons ACCT-TYPE-EQUITY (list ACCT-TYPE-EQUITY))
 	(cons ACCT-TYPE-INCOME (list ACCT-TYPE-INCOME))
-	(cons ACCT-TYPE-EXPENSE (list ACCT-TYPE-EXPENSE)))))
+	(cons ACCT-TYPE-EXPENSE (list ACCT-TYPE-EXPENSE))
+	(cons ACCT-TYPE-TRADING (list ACCT-TYPE-TRADING)))))
 
 ;; Returns the name of the account type as a string, and in its plural
 ;; form (as opposed to xaccAccountGetTypeStr which gives the
@@ -120,7 +121,8 @@
     (cons ACCT-TYPE-MONEYMRKT (_ "Money Market"))
     (cons ACCT-TYPE-RECEIVABLE (_ "Accounts Receivable"))
     (cons ACCT-TYPE-PAYABLE (_ "Accounts Payable"))
-    (cons ACCT-TYPE-CREDITLINE (_ "Credit Lines")))
+    (cons ACCT-TYPE-CREDITLINE (_ "Credit Lines"))
+    (cons ACCT-TYPE-TRADING (_ "Trading Accounts")))
    type))
 
 ;; Get the list of all different commodities that are used within the
Index: src/libqof/qof/qofbook.c
===================================================================
--- src/libqof/qof/qofbook.c	(revision 18399)
+++ src/libqof/qof/qofbook.c	(working copy)
@@ -39,6 +39,7 @@
 #include <string.h>
 
 #include <glib.h>
+#include <libguile.h>
 
 #include "qof.h"
 #include "qofevent-p.h"
@@ -439,6 +440,48 @@
     return counter;
 }
 
+static char *get_scm_string(const char *str_name)
+{
+    SCM scm_string = scm_c_eval_string (str_name);
+    if (! SCM_STRINGP(scm_string))
+        return NULL;
+        
+    return g_strdup(SCM_STRING_CHARS(scm_string));
+}
+
+/* Determine whether this book uses trading accounts */
+gboolean qof_book_use_trading_accounts (const QofBook *book)
+{
+    static char *options_name = NULL;
+    static char *acct_section = NULL;
+    static char *trading_opt = NULL;
+    
+    const char *opt;
+    kvp_value *kvp_val;
+    
+    if (options_name == NULL)
+    {
+        options_name = get_scm_string ("(car gnc:*kvp-option-path*)");
+        acct_section = get_scm_string ("gnc:*book-label*");
+        trading_opt = get_scm_string ("gnc:*trading-accounts*");
+        if (options_name == NULL || acct_section == NULL || trading_opt == NULL)
+        {
+            PWARN ("Unable to find trading account preference");
+        }
+    }
+    
+    kvp_val = kvp_frame_get_slot_path (qof_book_get_slots (book), options_name, acct_section,
+                                       trading_opt, NULL);
+    if (kvp_val == NULL)
+        return FALSE;
+    
+    opt = kvp_value_get_string (kvp_val);
+    
+    if (opt && opt[0] == 't' && opt[1] == 0)
+        return TRUE;
+    return FALSE;
+}
+
 /* QofObject function implementation and registration */
 gboolean qof_book_register (void)
 {
Index: src/libqof/qof/qofbook.h
===================================================================
--- src/libqof/qof/qofbook.h	(revision 18399)
+++ src/libqof/qof/qofbook.h	(working copy)
@@ -213,6 +213,9 @@
 /** Retrieves arbitrary pointers to structs stored by qof_book_set_data. */
 gpointer qof_book_get_data (const QofBook *book, const gchar *key);
 
+/** Returns flag indicating whether this book uses trading accounts */
+gboolean qof_book_use_trading_accounts (const QofBook *book);
+
 /** Is the book shutting down? */
 gboolean qof_book_shutting_down (const QofBook *book);
 
Index: src/business/business-utils/business-prefs.scm
===================================================================
--- src/business/business-utils/business-prefs.scm	(revision 18399)
+++ src/business/business-utils/business-prefs.scm	(working copy)
@@ -81,6 +81,12 @@
     gnc:*business-label* (N_ "Fancy Date Format")
     "g" (N_ "The default date format used for fancy printed dates")
     #f))
+    
+  (reg-option 
+   (gnc:make-simple-boolean-option
+    gnc:*book-label* gnc:*trading-accounts*
+    "a" (N_ "True if trading accounts should be used for transactions involving more than one commodity")
+    #f))
 )
 
 (gnc-register-kvp-option-generator QOF-ID-BOOK-SCM book-options-generator)
Index: src/business/business-utils/business-utils.scm
===================================================================
--- src/business/business-utils/business-utils.scm	(revision 18399)
+++ src/business/business-utils/business-utils.scm	(working copy)
@@ -18,5 +18,10 @@
             gnc:*company-phone* gnc:*company-fax* gnc:*company-url*
             gnc:*company-email* gnc:*company-contact*)
 
+(define gnc:*book-label* (N_ "Accounts"))
+(define gnc:*trading-accounts* (N_ "Trading Accounts"))
+
+(export gnc:*book-label* gnc:*trading-accounts*)
+
 (load-from-path "business-options.scm")
 (load-from-path "business-prefs.scm")
Index: src/business/business-ledger/gncEntryLedgerLoad.c
===================================================================
--- src/business/business-ledger/gncEntryLedgerLoad.c	(revision 18399)
+++ src/business/business-ledger/gncEntryLedgerLoad.c	(working copy)
@@ -134,7 +134,7 @@
   type = xaccAccountGetType (account);
   if (type == ACCT_TYPE_PAYABLE || type == ACCT_TYPE_RECEIVABLE ||
       type == ACCT_TYPE_CASH || type == ACCT_TYPE_BANK ||
-      type == ACCT_TYPE_EQUITY)
+      type == ACCT_TYPE_EQUITY || type == ACCT_TYPE_TRADING)
   {
     return TRUE;
   }
@@ -157,7 +157,7 @@
   type = xaccAccountGetType (account);
   if (type == ACCT_TYPE_PAYABLE || type == ACCT_TYPE_RECEIVABLE ||
       type == ACCT_TYPE_CASH || type == ACCT_TYPE_BANK ||
-      type == ACCT_TYPE_EQUITY)
+      type == ACCT_TYPE_EQUITY || type == ACCT_TYPE_TRADING)
   {
     return TRUE;
   }
Index: src/gnome-utils/window-main-summarybar.c
===================================================================
--- src/gnome-utils/window-main-summarybar.c	(revision 18399)
+++ src/gnome-utils/window-main-summarybar.c	(working copy)
@@ -293,6 +293,12 @@
       case ACCT_TYPE_EQUITY:
         /* no-op, see comments at top about summing assets */
 	break;
+      /**
+       * @fixme I don't know if this is right or if trading accounts should be
+       *        treated like income and expense accounts.
+       **/
+      case ACCT_TYPE_TRADING:
+        break;
       case ACCT_TYPE_CURRENCY:
       default:
 	break;
Index: src/gnome-utils/dialog-account.c
===================================================================
--- src/gnome-utils/dialog-account.c	(revision 18399)
+++ src/gnome-utils/dialog-account.c	(working copy)
@@ -169,7 +169,9 @@
 {
   dialog_commodity_mode new_mode;
 
-  if ((aw->type == ACCT_TYPE_STOCK) || (aw->type == ACCT_TYPE_MUTUAL))
+  if (aw->type == ACCT_TYPE_TRADING)
+    new_mode = DIAG_COMM_ALL;
+  else if ((aw->type == ACCT_TYPE_STOCK) || (aw->type == ACCT_TYPE_MUTUAL))
     new_mode = DIAG_COMM_NON_CURRENCY;
   else
     new_mode = DIAG_COMM_CURRENCY;
@@ -1026,7 +1028,8 @@
     sensitive = (aw->type != ACCT_TYPE_EQUITY &&
 		 aw->type != ACCT_TYPE_CURRENCY &&
 		 aw->type != ACCT_TYPE_STOCK &&
-		 aw->type != ACCT_TYPE_MUTUAL);
+		 aw->type != ACCT_TYPE_MUTUAL &&
+		 aw->type != ACCT_TYPE_TRADING);
   }
 
   gtk_widget_set_sensitive (aw->opening_balance_page, sensitive);
Index: src/gnome-utils/dialog-transfer.c
===================================================================
--- src/gnome-utils/dialog-transfer.c	(revision 18399)
+++ src/gnome-utils/dialog-transfer.c	(working copy)
@@ -2146,6 +2146,19 @@
 
     g_return_val_if_fail(txn_cur, TRUE);
 
+    if (xaccTransUseTradingAccounts (txn)) {
+      /* If we're using commodity trading accounts then "amount" is
+         really the split's amount and it's in xfer_com.  We need an
+         exchange rate that will convert this amount into a value in
+         the transaction currency.  */
+      if (gnc_commodity_equal(xfer_com, txn_cur)) {
+        /* Transaction is in the same currency as the split, exchange
+           rate is 1. */
+        *exch_rate = gnc_numeric_create(1, 1);
+        return FALSE;
+      }
+      swap_amounts = TRUE;
+    
     /* We know that "amount" is always in the reg_com currency.
      * Unfortunately it is possible that neither xfer_com or txn_cur are
      * the same as reg_com, in which case we need to convert to the txn
@@ -2153,7 +2166,7 @@
      * need to flip-flop the commodities and the exchange rates.
      */
     
-    if (gnc_commodity_equal(reg_com, txn_cur)) {
+    } else if (gnc_commodity_equal(reg_com, txn_cur)) {
         /* we're working in the txn currency.  Great.  Nothing to do! */
         swap_amounts = FALSE;
         
Index: src/gnome/druid-hierarchy.c
===================================================================
--- src/gnome/druid-hierarchy.c	(revision 18399)
+++ src/gnome/druid-hierarchy.c	(working copy)
@@ -706,7 +706,8 @@
 		string = xaccPrintAmount (balance, print_info);
 	}
 
- 	if (xaccAccountGetType(account) == ACCT_TYPE_EQUITY) {
+ 	if (xaccAccountGetType(account) == ACCT_TYPE_EQUITY ||
+ 	    xaccAccountGetType(account) == ACCT_TYPE_TRADING) {
 	  allow_value = FALSE;
 	  string=_("zero");
 	} else {
Index: src/engine/ScrubP.h
===================================================================
--- src/engine/ScrubP.h	(revision 18399)
+++ src/engine/ScrubP.h	(working copy)
@@ -34,7 +34,8 @@
 
 /* Utility to make account by name.  Not for public use. */
 Account * xaccScrubUtilityGetOrMakeAccount (Account *root, 
-       gnc_commodity * currency, const char *name_root);
+       gnc_commodity * currency, const char *accname,
+       GNCAccountType acctype, gboolean placeholder);
 
 
 #endif /* XACC_SCRUB_P_H */
Index: src/engine/engine.i
===================================================================
--- src/engine/engine.i	(revision 18399)
+++ src/engine/engine.i	(working copy)
@@ -227,6 +227,8 @@
     SET_ENUM("ACCT-TYPE-EQUITY");
     SET_ENUM("ACCT-TYPE-RECEIVABLE");
     SET_ENUM("ACCT-TYPE-PAYABLE");
+    SET_ENUM("ACCT-TYPE-ROOT");
+    SET_ENUM("ACCT-TYPE-TRADING");
     SET_ENUM("NUM-ACCOUNT-TYPES");
     SET_ENUM("ACCT-TYPE-CHECKING");
     SET_ENUM("ACCT-TYPE-SAVINGS");
Index: src/engine/Account.c
===================================================================
--- src/engine/Account.c	(revision 18399)
+++ src/engine/Account.c	(working copy)
@@ -1898,7 +1898,7 @@
      ACCT_TYPE_BANK, ACCT_TYPE_STOCK, ACCT_TYPE_MUTUAL, ACCT_TYPE_CURRENCY,
      ACCT_TYPE_CASH, ACCT_TYPE_ASSET, ACCT_TYPE_RECEIVABLE,
      ACCT_TYPE_CREDIT, ACCT_TYPE_LIABILITY, ACCT_TYPE_PAYABLE,
-     ACCT_TYPE_INCOME, ACCT_TYPE_EXPENSE, ACCT_TYPE_EQUITY };
+     ACCT_TYPE_INCOME, ACCT_TYPE_EXPENSE, ACCT_TYPE_EQUITY, ACCT_TYPE_TRADING };
 
 static int revorder[NUM_ACCOUNT_TYPES] = {
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
@@ -3642,6 +3642,7 @@
     GNC_RETURN_ENUM_AS_STRING(RECEIVABLE);
     GNC_RETURN_ENUM_AS_STRING(PAYABLE);
     GNC_RETURN_ENUM_AS_STRING(ROOT);
+    GNC_RETURN_ENUM_AS_STRING(TRADING);
     GNC_RETURN_ENUM_AS_STRING(CHECKING);
     GNC_RETURN_ENUM_AS_STRING(SAVINGS);
     GNC_RETURN_ENUM_AS_STRING(MONEYMRKT);
@@ -3677,6 +3678,7 @@
   GNC_RETURN_ON_MATCH(RECEIVABLE);
   GNC_RETURN_ON_MATCH(PAYABLE);
   GNC_RETURN_ON_MATCH(ROOT);
+  GNC_RETURN_ON_MATCH(TRADING);
   GNC_RETURN_ON_MATCH(CHECKING);
   GNC_RETURN_ON_MATCH(SAVINGS);
   GNC_RETURN_ON_MATCH(MONEYMRKT);
@@ -3718,7 +3720,9 @@
   N_("Expense"),
   N_("Equity"),
   N_("A/Receivable"),
-  N_("A/Payable")
+  N_("A/Payable"),
+  N_("Root"),
+  N_("Trading")
   /*
     N_("Checking"),
     N_("Savings"),
@@ -3790,6 +3794,10 @@
     return
       (1 << ACCT_TYPE_EQUITY)     |
       (1 << ACCT_TYPE_ROOT);
+  case ACCT_TYPE_TRADING:
+    return
+      (1 << ACCT_TYPE_TRADING)    |
+      (1 << ACCT_TYPE_ROOT);
   default:
     PERR("bad account type: %d", type);
     return 0;
Index: src/engine/Account.h
===================================================================
--- src/engine/Account.h	(revision 18399)
+++ src/engine/Account.h	(working copy)
@@ -140,18 +140,24 @@
   ACCT_TYPE_PAYABLE = 12,  /**< A/P account type */
 
   ACCT_TYPE_ROOT = 13, /**< The hidden root account of an account tree. */
+  
+  ACCT_TYPE_TRADING = 14, /**< Account used to record multiple commodity transactions.
+                           *   This is not the same as ACCT_TYPE_CURRENCY above.
+                           *   Multiple commodity transactions have splits in these
+                           *   accounts to make the transaction balance in each 
+                           *   commodity as well as in total value.  */
 
-  NUM_ACCOUNT_TYPES = 14,  /**< stop here; the following types
+  NUM_ACCOUNT_TYPES = 15,  /**< stop here; the following types
 			    * just aren't ready for prime time */
   
   /* bank account types */
-  ACCT_TYPE_CHECKING = 14, /**< bank account type -- don't use this
+  ACCT_TYPE_CHECKING = 15, /**< bank account type -- don't use this
 			    *   for now, see NUM_ACCOUNT_TYPES  */
-  ACCT_TYPE_SAVINGS = 15, /**< bank account type -- don't use this for
+  ACCT_TYPE_SAVINGS = 16, /**< bank account type -- don't use this for
 			   *   now, see NUM_ACCOUNT_TYPES  */
-  ACCT_TYPE_MONEYMRKT = 16, /**< bank account type -- don't use this
+  ACCT_TYPE_MONEYMRKT = 17, /**< bank account type -- don't use this
 			     *   for now, see NUM_ACCOUNT_TYPES  */
-  ACCT_TYPE_CREDITLINE = 17, /**< line of credit -- don't use this for
+  ACCT_TYPE_CREDITLINE = 18, /**< line of credit -- don't use this for
 			      *   now, see NUM_ACCOUNT_TYPES  */
 } GNCAccountType;
 
Index: src/engine/Scrub.c
===================================================================
--- src/engine/Scrub.c	(revision 18399)
+++ src/engine/Scrub.c	(working copy)
@@ -72,6 +72,7 @@
 TransScrubOrphansFast (Transaction *trans, Account *root)
 {
   GList *node;
+  gchar *accname;
 
   if (!trans) return;
   g_return_if_fail (root);
@@ -85,7 +86,12 @@
 
     DEBUG ("Found an orphan \n");
 
-    orph = xaccScrubUtilityGetOrMakeAccount (root, trans->common_currency, _("Orphan"));
+    accname = g_strconcat (_("Orphan"), "-",
+                           gnc_commodity_get_mnemonic (trans->common_currency), 
+                           NULL);
+    orph = xaccScrubUtilityGetOrMakeAccount (root, trans->common_currency, 
+                                             accname, ACCT_TYPE_BANK, FALSE);
+    g_free (accname);
     if (!orph) continue;
 
     xaccSplitSetAccount(split, orph);
@@ -353,28 +359,15 @@
   }
 }
 
-void
-xaccTransScrubImbalance (Transaction *trans, Account *root,
-                         Account *account)
+static Split *
+get_balance_split (Transaction *trans, Account *root, Account *account,
+                     gnc_commodity *commodity)
 {
-  Split *balance_split = NULL;
-  gnc_numeric imbalance;
-
-  if (!trans) return;
-
-  ENTER ("()");
-
-  /* Must look for orphan splits even if there is no imbalance. */
-  xaccTransScrubSplits (trans);
-
-  /* If the transaction is balanced, nothing more to do */
-  imbalance = xaccTransGetImbalance (trans);
-  if (gnc_numeric_zero_p (imbalance)) {
-    LEAVE("zero imbalance");
-    return;
-  }
-
-  if (!account)
+  Split *balance_split;
+  gchar *accname;
+  
+  if (!account ||
+      !gnc_commodity_equiv (commodity, xaccAccountGetCommodity(account)))
   {
     if (!root) 
     {
@@ -383,16 +376,17 @@
        {
           /* This can't occur, things should be in books */
           PERR ("Bad data corruption, no root account in book");
-          LEAVE("");
-          return;
+          return NULL;
        }
     }
-    account = xaccScrubUtilityGetOrMakeAccount (root, 
-        trans->common_currency, _("Imbalance"));
+    accname = g_strconcat (_("Imbalance"), "-",
+                           gnc_commodity_get_mnemonic (commodity), NULL);
+    account = xaccScrubUtilityGetOrMakeAccount (root, commodity, 
+                                                accname, ACCT_TYPE_BANK, FALSE);
+    g_free (accname);
     if (!account) {
         PERR ("Can't get balancing account");
-        LEAVE("");
-        return;
+        return NULL;
     }
   }
 
@@ -408,36 +402,403 @@
     xaccSplitSetAccount(balance_split, account);
     xaccTransCommitEdit (trans);
   }
+  
+  return balance_split;
+}
 
-  PINFO ("unbalanced transaction");
+/* Get the trading split for a given commodity, creating it (and the 
+   necessary accounts) if it doesn't exist. */
+static Split *
+get_trading_split (Transaction *trans, Account *root, 
+                   gnc_commodity *commodity)
+{
+  Split *balance_split;
+  Account *trading_account;
+  Account *ns_account;
+  Account *account;
+  gnc_commodity *default_currency = NULL;
+  
+  if (!root) 
+  {
+    root = gnc_book_get_root_account (xaccTransGetBook (trans));
+    if (NULL == root)
+    {
+      /* This can't occur, things should be in books */
+      PERR ("Bad data corruption, no root account in book");
+      return NULL;
+    }
+  }
+  
+  /* Get the default currency.  This is harder than it seems.  It's not
+     possible to call gnc_default_currency() since it's a UI function.  One
+     might think that the currency of the root account would do, but the root
+     account has no currency.  Instead look for the Income placeholder account
+     and use its currency.  */
+  default_currency = xaccAccountGetCommodity(gnc_account_lookup_by_name(root, 
+                                                                        _("Income")));
+  if (! default_currency) {
+    default_currency = commodity;
+  }
+  
+  trading_account = xaccScrubUtilityGetOrMakeAccount (root, 
+                                                      default_currency,
+                                                      _("Trading"),
+                                                      ACCT_TYPE_TRADING, TRUE);
+  if (!trading_account) {
+    PERR ("Can't get trading account");
+    return NULL;
+  }
+  
+  ns_account = xaccScrubUtilityGetOrMakeAccount (trading_account,
+                                                 default_currency,
+                                                 gnc_commodity_get_namespace(commodity),
+                                                 ACCT_TYPE_TRADING, TRUE);
+  if (!ns_account) {
+    PERR ("Can't get namespace account");
+    return NULL;
+  }
+  
+  account = xaccScrubUtilityGetOrMakeAccount (ns_account, commodity,
+                                              gnc_commodity_get_mnemonic(commodity),
+                                              ACCT_TYPE_TRADING, FALSE);
+  if (!account) {
+    PERR ("Can't get commodity account");
+    return NULL;
+  }
+  
+  
+  balance_split = xaccTransFindSplitByAccount(trans, account);
+  
+  /* Put split into account before setting split value */
+  if (!balance_split)
+  {
+    balance_split = xaccMallocSplit (qof_instance_get_book(trans));
+    
+    xaccTransBeginEdit (trans);
+    xaccSplitSetParent(balance_split, trans);
+    xaccSplitSetAccount(balance_split, account);
+    xaccTransCommitEdit (trans);
+  }
+  
+  return balance_split;
+}
 
+/* Find the trading split for a commodity, but don't create any splits
+   or accounts if they don't already exist. */
+static Split *
+find_trading_split (Transaction *trans, Account *root, 
+                    gnc_commodity *commodity)
+{
+  Account *trading_account;
+  Account *ns_account;
+  Account *account;
+  
+  if (!root) 
   {
-    const gnc_commodity *currency;
-    const gnc_commodity *commodity;
-    gnc_numeric old_value, new_value;
+    root = gnc_book_get_root_account (xaccTransGetBook (trans));
+    if (NULL == root)
+    {
+      /* This can't occur, things should be in books */
+      PERR ("Bad data corruption, no root account in book");
+      return NULL;
+    }
+  }
+  
+  trading_account = gnc_account_lookup_by_name (root, _("Trading"));
+  if (!trading_account) {
+    return NULL;
+  }
+  
+  ns_account = gnc_account_lookup_by_name (trading_account,
+                                           gnc_commodity_get_namespace(commodity));
+  if (!ns_account) {
+    return NULL;
+  }
+  
+  account = gnc_account_lookup_by_name (ns_account,
+                                        gnc_commodity_get_mnemonic(commodity));
+  if (!account) {
+    return NULL;
+  }
+  
+  return xaccTransFindSplitByAccount(trans, account);
+}
 
-    xaccTransBeginEdit (trans);
+static void
+add_balance_split (Transaction *trans, gnc_numeric imbalance,
+                   Account *root, Account *account)
+{
+  const gnc_commodity *commodity;
+  gnc_numeric old_value, new_value;
+  Split *balance_split;
+  gnc_commodity *currency = xaccTransGetCurrency (trans);
+  
+  balance_split = get_balance_split(trans, root, account, currency);
+  if (!balance_split)
+  {
+    /* Error already logged */
+    LEAVE("");
+    return;
+  }
+  account = xaccSplitGetAccount(balance_split);
+  
+  xaccTransBeginEdit (trans);
+  
+  old_value = xaccSplitGetValue (balance_split);
+  
+  /* Note: We have to round for the commodity's fraction, NOT any
+    * already existing denominator (bug #104343), because either one
+    * of the denominators might already be reduced.  */
+  new_value = gnc_numeric_sub (old_value, imbalance,
+                               gnc_commodity_get_fraction(currency), 
+                               GNC_HOW_RND_ROUND);
+  
+  xaccSplitSetValue (balance_split, new_value);
+  
+  commodity = xaccAccountGetCommodity (account);
+  if (gnc_commodity_equiv (currency, commodity))
+  {
+    xaccSplitSetAmount (balance_split, new_value);
+  }
+  
+  xaccSplitScrub (balance_split);
+  xaccTransCommitEdit (trans);
+}
 
-    currency = xaccTransGetCurrency (trans);
-    old_value = xaccSplitGetValue (balance_split);
+void
+xaccTransScrubImbalance (Transaction *trans, Account *root,
+                         Account *account)
+{
+  const gnc_commodity *currency;
 
-    /* Note: We have to round for the commodity's fraction, NOT any
-     * already existing denominator (bug #104343), because either one
-     * of the denominators might already be reduced.  */
-    new_value = gnc_numeric_sub (old_value, imbalance,
-             gnc_commodity_get_fraction(currency), 
-             GNC_HOW_RND_ROUND);
+  if (!trans) return;
 
-    xaccSplitSetValue (balance_split, new_value);
+  ENTER ("()");
 
-    commodity = xaccAccountGetCommodity (account);
-    if (gnc_commodity_equiv (currency, commodity))
+  /* Must look for orphan splits even if there is no imbalance. */
+  xaccTransScrubSplits (trans);
+
+  /* Return immediately if things are balanced. */
+  if (xaccTransIsBalanced (trans))
+    return;
+
+  currency = xaccTransGetCurrency (trans);
+
+  if (! xaccTransUseTradingAccounts (trans))
+  {
+    gnc_numeric imbalance;
+
+    /* Make the value sum to zero */
+    imbalance = xaccTransGetImbalanceValue (trans);
+    if (! gnc_numeric_zero_p (imbalance))
     {
-      xaccSplitSetAmount (balance_split, new_value);
+      PINFO ("Value unbalanced transaction");
+
+      add_balance_split (trans, imbalance, root, account);
     }
+  }
+  else
+  {
+    MonetaryList *imbal_list;
+    MonetaryList *imbalance_commod;
+    GList *splits;
+    gnc_numeric imbalance;
+    Split *balance_split = NULL;
+   
+    /* If there are existing trading splits, adjust the price or exchange
+       rate in each of them to agree with the non-trading splits for the
+       same commodity.  If there are multiple non-trading splits for the 
+       same commodity in the transaction this will use the exchange rate in
+       the last such split.  This shouldn't happen, and if it does then there's
+       not much we can do about it anyway.
+      
+       While we're at it, compute the value imbalance ignoring existing
+       trading splits. */
+    
+    imbalance = gnc_numeric_zero();
+    
+    for (splits = trans->splits; splits; splits = splits->next) 
+    {
+      Split *split = splits->data;
+      gnc_numeric value, amount;
+      gnc_commodity *commodity;
+      
+      if (! xaccTransStillHasSplit (trans, split)) continue;
+      
+      commodity = xaccAccountGetCommodity (xaccSplitGetAccount(split));
+      if (!commodity) 
+      {
+        PERR("Split has no commodity");
+        continue;
+      }
+      
+      balance_split = find_trading_split (trans, root, commodity);
+      
+      if (balance_split != split)
+        /* this is not a trading split */
+        imbalance = gnc_numeric_add(imbalance, xaccSplitGetValue (split),
+                                    GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
+      
+      /* Ignore splits where value or amount is zero */
+      value = xaccSplitGetValue (split);
+      amount = xaccSplitGetAmount (split);
+      if (gnc_numeric_zero_p(amount) || gnc_numeric_zero_p(value))
+        continue;
+      
+      if (balance_split && balance_split != split) 
+      {
+        gnc_numeric convrate = gnc_numeric_div (amount, value, 
+                                                GNC_DENOM_AUTO, GNC_DENOM_REDUCE);
+        gnc_numeric old_value, new_value;
+        old_value = xaccSplitGetValue(balance_split);
+        new_value = gnc_numeric_div (xaccSplitGetAmount(balance_split), 
+                                     convrate,
+                                     gnc_commodity_get_fraction(currency),
+                                     GNC_RND_ROUND);
+        if (! gnc_numeric_equal (old_value, new_value)) 
+        {
+          xaccTransBeginEdit (trans);
+          xaccSplitSetValue (balance_split, new_value);
+          xaccSplitScrub (balance_split);
+          xaccTransCommitEdit (trans);
+        }
+      }
+    }
 
-    xaccSplitScrub (balance_split);
-    xaccTransCommitEdit (trans);
+    /* Balance the value, ignoring existing trading splits */
+    if (! gnc_numeric_zero_p (imbalance))
+    {
+      PINFO ("Value unbalanced transaction");
+      
+      add_balance_split (trans, imbalance, root, account);
+    }
+    
+    /* If the transaction is balanced, nothing more to do */
+    imbal_list = xaccTransGetImbalance (trans);
+    if (!imbal_list) 
+    {
+      LEAVE("()");
+      return;
+    }
+  
+    PINFO ("Currency unbalanced transaction");
+    
+    for (imbalance_commod = imbal_list; imbalance_commod; 
+         imbalance_commod = imbalance_commod->next) {
+      gnc_monetary *imbal_mon = imbalance_commod->data;
+      gnc_commodity *commodity;
+      gnc_numeric convrate;
+      gnc_numeric old_amount, new_amount;
+      gnc_numeric old_value, new_value, val_imbalance;
+      GList *splits;
+      
+      commodity = gnc_monetary_commodity (*imbal_mon);
+      
+      balance_split = get_trading_split(trans, root, commodity);
+      if (!balance_split)
+      {
+        /* Error already logged */
+        gnc_monetary_list_free(imbal_list);
+        LEAVE("");
+        return;
+      }
+      
+      account = xaccSplitGetAccount(balance_split);
+      
+      if (! gnc_commodity_equal (currency, commodity)) {
+        /* Find the value imbalance in this commodity */
+        val_imbalance = gnc_numeric_zero();
+        for (splits = trans->splits; splits; splits = splits->next) {
+          Split *split = splits->data;
+          if (xaccTransStillHasSplit (trans, split) &&
+              gnc_commodity_equal (commodity, 
+                                   xaccAccountGetCommodity(xaccSplitGetAccount(split))))
+            val_imbalance = gnc_numeric_add (val_imbalance, xaccSplitGetValue (split),
+                                             GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
+        }
+      }
+      
+      xaccTransBeginEdit (trans);
+      
+      old_amount = xaccSplitGetAmount (balance_split);
+      new_amount = gnc_numeric_sub (old_amount, gnc_monetary_value(*imbal_mon),
+                                    gnc_commodity_get_fraction(commodity), 
+                                    GNC_HOW_RND_ROUND);
+      
+      xaccSplitSetAmount (balance_split, new_amount);
+      
+      if (gnc_commodity_equal (currency, commodity)) {
+        /* Imbalance commodity is the transaction currency, value in the
+           split must be the same as the amount */
+        xaccSplitSetValue (balance_split, new_amount);
+      }
+      else {
+        old_value = xaccSplitGetValue (balance_split);
+        new_value = gnc_numeric_sub (old_value, val_imbalance,
+                                     gnc_commodity_get_fraction(currency), 
+                                     GNC_HOW_RND_ROUND);
+                                     
+        xaccSplitSetValue (balance_split, new_value);
+      }
+      
+      xaccSplitScrub (balance_split);
+      xaccTransCommitEdit (trans);     
+    }
+       
+    gnc_monetary_list_free(imbal_list);
+    
+    if (!gnc_numeric_zero_p(xaccTransGetImbalanceValue(trans))) {
+      /* This is probably because there are splits with zero amount
+         and non-zero value.  These are usually realized gain/loss
+         splits.  Add a reversing split for each of them to balance
+         the value. */
+
+      /* Copy the split list so we don't see the splits we're adding */
+      GList *splits_dup = g_list_copy(trans->splits);
+      for (splits = splits_dup; splits; splits = splits->next) {
+        Split *split = splits->data;
+        if (! xaccTransStillHasSplit(trans, split)) continue;
+        if (!gnc_numeric_zero_p(xaccSplitGetValue(split)) &&
+            gnc_numeric_zero_p(xaccSplitGetAmount(split))) {
+          gnc_commodity *commodity;
+          gnc_numeric old_value, new_value;
+
+          commodity = xaccAccountGetCommodity(xaccSplitGetAccount(split));
+          if (!commodity) {
+            PERR("Split has no commodity");
+            continue;
+          }
+          balance_split = get_trading_split(trans, root, commodity);
+          if (!balance_split)
+          {
+            /* Error already logged */
+            gnc_monetary_list_free(imbal_list);
+            LEAVE("");
+            return;
+          }
+          account = xaccSplitGetAccount(balance_split);
+          
+          xaccTransBeginEdit (trans);
+          
+          old_value = xaccSplitGetValue (balance_split);
+          new_value = gnc_numeric_sub (old_value, xaccSplitGetValue(split),
+                                       gnc_commodity_get_fraction(currency), 
+                                       GNC_HOW_RND_ROUND);
+          xaccSplitSetValue (balance_split, new_value);
+          
+          /* Don't change the balance split's amount since the amount
+             is zero in the split we're working on */
+
+          xaccSplitScrub (balance_split);
+          xaccTransCommitEdit (trans);     
+        }
+      }
+      
+      g_list_free(splits_dup);
+      
+      if (!gnc_numeric_zero_p(xaccTransGetImbalanceValue(trans)))
+        PERR("Balancing currencies unbalanced value");
+    }
   }
   LEAVE ("()");
 }
@@ -836,9 +1197,9 @@
 
 Account *
 xaccScrubUtilityGetOrMakeAccount (Account *root, gnc_commodity * currency,
-                  const char *name_root)
+                                  const char *accname, GNCAccountType acctype,
+                                  gboolean placeholder)
 {
-  char * accname;
   Account * acc;
 
   g_return_val_if_fail (root, NULL);
@@ -850,9 +1211,6 @@
     return NULL;
   }
 
-  accname = g_strconcat (name_root, "-",
-                         gnc_commodity_get_mnemonic (currency), NULL);
-
   /* See if we've got one of these going already ... */
   acc = gnc_account_lookup_by_name(root, accname);
 
@@ -863,15 +1221,14 @@
     xaccAccountBeginEdit (acc);
     xaccAccountSetName (acc, accname);
     xaccAccountSetCommodity (acc, currency);
-    xaccAccountSetType (acc, ACCT_TYPE_BANK);
+    xaccAccountSetType (acc, acctype);
+    xaccAccountSetPlaceholder (acc, placeholder);
 
     /* Hang the account off the root. */
     gnc_account_append_child (root, acc);
     xaccAccountCommitEdit (acc);
   }
 
-  g_free (accname);
-
   return acc;
 }
 
Index: src/engine/Period.c
===================================================================
--- src/engine/Period.c	(revision 18399)
+++ src/engine/Period.c	(working copy)
@@ -689,7 +689,7 @@
       /* We need to carry a balance on any account that is not
        * and income or expense or equity account */
       if ((ACCT_TYPE_INCOME != tip) && (ACCT_TYPE_EXPENSE != tip) &&
-	  (ACCT_TYPE_EQUITY != tip)) 
+	  (ACCT_TYPE_EQUITY != tip && ACCT_TYPE_TRADING != tip)) 
       {
          gnc_numeric baln;
          baln = xaccAccountGetBalance (candidate);
Index: src/engine/Transaction.c
===================================================================
--- src/engine/Transaction.c	(revision 18399)
+++ src/engine/Transaction.c	(working copy)
@@ -650,8 +650,20 @@
 }
 
 /********************************************************************\
+xaccTransUseTradingAccounts
+
+Returns true if the transaction should include trading account splits if
+it involves more than one commodity.
 \********************************************************************/
 
+gboolean xaccTransUseTradingAccounts(const Transaction *trans)
+{
+  return qof_book_use_trading_accounts(qof_instance_get_book (trans));
+}
+
+/********************************************************************\
+\********************************************************************/
+
 Transaction *
 xaccTransLookup (const GUID *guid, QofBook *book)
 {
@@ -665,7 +677,7 @@
 \********************************************************************/
 
 gnc_numeric
-xaccTransGetImbalance (const Transaction * trans)
+xaccTransGetImbalanceValue (const Transaction * trans)
 {
   gnc_numeric imbal = gnc_numeric_zero();
   if (!trans) return imbal;
@@ -680,6 +692,91 @@
   return imbal;
 }
 
+MonetaryList *
+xaccTransGetImbalance (const Transaction * trans)
+{
+  /* imbal_value is used if either (1) the transaction has a non currency
+     split or (2) all the splits are in the same currency.  If there are 
+     no non-currency splits and not all splits are in the same currency then
+     imbal_list is used to compute the imbalance. */
+  MonetaryList *imbal_list = NULL;
+  gnc_numeric imbal_value = gnc_numeric_zero();
+  gboolean trading_accts;
+  
+  if (!trans) return imbal_list;
+  
+  ENTER("(trans=%p)", trans);
+  
+  trading_accts = xaccTransUseTradingAccounts (trans);
+  
+  /* If using trading accounts and there is at least one split that is not
+     in the transaction currency or a split that has a price or exchange 
+     rate other than 1, then compute the balance in each commodity in the
+     transaction.  Otherwise (all splits are in the transaction's currency)
+     then compute the balance using the value fields.
+     
+     Optimize for the common case of only one currency and a balanced 
+     transaction. */
+  FOR_EACH_SPLIT(trans, {
+    gnc_commodity *commodity;
+    commodity = xaccAccountGetCommodity(xaccSplitGetAccount(s));
+    if (trading_accts && 
+        (imbal_list ||
+         ! gnc_commodity_equiv(commodity, trans->common_currency) ||
+         ! gnc_numeric_equal(xaccSplitGetAmount(s), xaccSplitGetValue(s)))) {
+      /* Need to use (or already are using) a list of imbalances in each of 
+         the currencies used in the transaction. */
+      if (! imbal_list) {
+        /* All previous splits have been in the transaction's common
+           currency, so imbal_value is in this currency. */
+        imbal_list = gnc_monetary_list_add_value(imbal_list, 
+                                                 trans->common_currency,
+                                                 imbal_value);
+      }
+      imbal_list = gnc_monetary_list_add_value(imbal_list, commodity,
+                                               xaccSplitGetAmount(s));
+    }
+    
+    /* Add it to the value accumulator in case we need it. */
+    imbal_value = gnc_numeric_add(imbal_value, xaccSplitGetValue(s),
+                                  GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
+  } );
+
+  
+  if (!imbal_list && !gnc_numeric_zero_p(imbal_value)) {
+    /* Not balanced and no list, create one.  If we found multiple currencies
+       and no non-currency commodity then imbal_list will already exist and
+       we won't get here. */
+    imbal_list = gnc_monetary_list_add_value(imbal_list,
+                                             trans->common_currency,
+                                             imbal_value);
+  }
+  
+  /* Delete all the zero entries from the list, perhaps leaving an
+     empty list */
+  imbal_list = gnc_monetary_list_delete_zeros(imbal_list);
+  
+  LEAVE("(trans=%p), imbal=%p", trans, imbal_list);
+  return imbal_list;
+}
+
+gboolean
+xaccTransIsBalanced (const Transaction *trans)
+{
+  MonetaryList *imbal_list;
+  gboolean result;
+  if (! gnc_numeric_zero_p(xaccTransGetImbalanceValue(trans)))
+    return FALSE;
+    
+  if (!xaccTransUseTradingAccounts (trans)) 
+    return TRUE;
+    
+  imbal_list = xaccTransGetImbalance(trans);
+  result = imbal_list == NULL;
+  gnc_monetary_list_free(imbal_list);
+  return result;
+}
+
 gnc_numeric
 xaccTransGetAccountValue (const Transaction *trans, 
                           const Account *acc)
@@ -716,22 +813,28 @@
   GList *splits;
   Split *s;
   gboolean found_acc_match = FALSE;
+  gnc_commodity *acc_commod = xaccAccountGetCommodity(acc);
 
   /* We need to compute the conversion rate into _this account_.  So,
    * find the first split into this account, compute the conversion
    * rate (based on amount/value), and then return this conversion
    * rate.
    */
-  if (gnc_commodity_equal(xaccAccountGetCommodity(acc), 
-                          xaccTransGetCurrency(txn)))
+  if (gnc_commodity_equal(acc_commod, xaccTransGetCurrency(txn)))
       return gnc_numeric_create(1, 1);
 
   for (splits = txn->splits; splits; splits = splits->next) {
+    Account *split_acc;
+    gnc_commodity *split_commod;
+    
     s = splits->data;
 
     if (!xaccTransStillHasSplit(txn, s))
       continue;
-    if (xaccSplitGetAccount (s) != acc)
+    split_acc = xaccSplitGetAccount (s);
+    split_commod = xaccAccountGetCommodity (split_acc);
+    if (! (split_acc == acc ||
+          gnc_commodity_equal (split_commod, acc_commod)))
       continue;
 
     found_acc_match = TRUE;
@@ -1932,7 +2035,7 @@
 static gboolean
 trans_is_balanced_p (const Transaction *trans)
 {
-  return trans ? gnc_numeric_zero_p(xaccTransGetImbalance(trans)) : FALSE;
+  return trans ? xaccTransIsBalanced(trans) : FALSE;
 }
 
 gboolean xaccTransRegister (void)
@@ -1954,7 +2057,7 @@
     { TRANS_DATE_DUE, QOF_TYPE_DATE, 
       (QofAccessFunc)xaccTransRetDateDueTS, NULL },
     { TRANS_IMBALANCE, QOF_TYPE_NUMERIC, 
-      (QofAccessFunc)xaccTransGetImbalance, NULL },
+      (QofAccessFunc)xaccTransGetImbalanceValue, NULL },
     { TRANS_NOTES, QOF_TYPE_STRING, 
       (QofAccessFunc)xaccTransGetNotes, 
       (QofSetterFunc)qofTransSetNotes },
Index: src/engine/Period.h
===================================================================
--- src/engine/Period.h	(revision 18399)
+++ src/engine/Period.h	(working copy)
@@ -48,7 +48,7 @@
  * 
  *    This routine will also create 'equity transactions' in 
  *    order to preserve the balances on accounts.  For any
- *    account that is not of income, expense or equity type,
+ *    account that is not of income, expense, trading or equity type,
  *    this routine wil find the closing balance of each account
  *    in the closed book.  It will then create an 'equity
  *    transaction' in the open book, creating an opening balance 
Index: src/engine/Transaction.h
===================================================================
--- src/engine/Transaction.h	(revision 18399)
+++ src/engine/Transaction.h	(working copy)
@@ -244,6 +244,10 @@
  @{
 */
 
+/** Determine whether this transaction should use commodity trading accounts
+ */
+gboolean xaccTransUseTradingAccounts(const Transaction *trans);
+
 /** Sorts the splits in a transaction, putting the debits first,
  *  followed by the credits.
  */
@@ -342,16 +346,35 @@
 /** Set the commodity of this transaction. */
 void xaccTransSetCurrency (Transaction *trans, gnc_commodity *curr);
 
-/** The xaccTransGetImbalance() method returns the total value of the
+/** The xaccTransGetImbalanceValue() method returns the total value of the
  * transaction.  In a pure double-entry system, this imbalance
  * should be exactly zero, and if it is not, something is broken.
  * However, when double-entry semantics are not enforced, unbalanced
  * transactions can sneak in, and this routine can be used to find
  * out how much things are off by.  The value returned is denominated
  * in the currency that is returned by the xaccTransFindCommonCurrency()
- * method. */
-gnc_numeric xaccTransGetImbalance (const Transaction * trans);
+ * method. 
+ *
+ * If the use of currency exchange accounts is enabled then the a 
+ * a transaction must be balanced in each currency it uses to be considered
+ * to be balanced.  The method xaccTransGetImbalance is used by most
+ * code to take this into consideration.  This method is only used in a few
+ * places that want the transaction value even if currency exchange accounts
+ * are enabled. */
+gnc_numeric xaccTransGetImbalanceValue (const Transaction * trans);
 
+/** The xaccTransGetImbalance method returns a list giving the value of 
+ * the transaction in each currency for which the balance is not zero. 
+ * If the use of currency accounts is disabled, then this will be only
+ * the common currency for the transaction and xaccTransGetImbalance
+ * becomes equivalent to xaccTransGetImbalanceValue.  Otherwise it will
+ * return a list containing the imbalance in each currency. */
+MonetaryList *xaccTransGetImbalance (const Transaction * trans);
+
+/** Returns true if the transaction is balanced according to the rules
+ * currently in effect. */
+gboolean xaccTransIsBalanced(const Transaction * trans);
+
 /** The xaccTransGetAccountValue() method returns the total value applied
  *  to a particular account.  In some cases there may be multiple Splits
  *  in a single Transaction applied to one account (in particular when
Index: src/engine/gnc-commodity.c
===================================================================
--- src/engine/gnc-commodity.c	(revision 18399)
+++ src/engine/gnc-commodity.c	(working copy)
@@ -2416,4 +2416,61 @@
   return qof_object_register (&commodity_table_object_def);
 }
 
+/* *******************************************************************
+*  gnc_monetary methods
+********************************************************************/
+
+/** Add a gnc_monetary to the list */
+MonetaryList *
+gnc_monetary_list_add_monetary(MonetaryList *list, gnc_monetary add_mon)
+{
+  MonetaryList *l = list, *tmp;
+  for (tmp = list; tmp; tmp = tmp->next) {
+    gnc_monetary *list_mon = tmp->data;
+    if (gnc_commodity_equiv(list_mon->commodity, add_mon.commodity)) {
+      list_mon->value = gnc_numeric_add(list_mon->value, add_mon.value,
+                                        GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
+      break;
+    }
+  }
+  
+  /* See if we found an entry, and add one if not */
+  if (tmp == NULL) {
+    gnc_monetary *new_mon = g_new0(gnc_monetary, 1);
+    *new_mon = add_mon;
+    l = g_list_prepend(l, new_mon);
+  }
+  
+  return l;
+}
+
+/** Delete all entries in the list that have zero value.  Return list
+    pointer will be a null pointer if there are no non-zero entries **/
+MonetaryList *
+gnc_monetary_list_delete_zeros(MonetaryList *list)
+{
+  MonetaryList *node, *next;
+  for (node = list; node; node = next) {
+    gnc_monetary *mon = node->data;
+    next = node->next;
+    if (gnc_numeric_zero_p(mon->value)) {
+      g_free(mon);
+      list = g_list_delete_link(list, node);
+    }
+  }
+  return list;
+}
+
+/** Free a MonetaryList and all the monetaries it points to */
+void
+gnc_monetary_list_free(MonetaryList *list)
+{
+  MonetaryList *tmp;
+  for (tmp = list; tmp; tmp = tmp->next) {
+    g_free(tmp->data);
+  }
+  
+  g_list_free(list);
+}
+
 /* ========================= END OF FILE ============================== */
Index: src/engine/gnc-commodity.h
===================================================================
--- src/engine/gnc-commodity.h	(revision 18399)
+++ src/engine/gnc-commodity.h	(working copy)
@@ -973,7 +973,71 @@
 		  
 /** @} */
 
+/** @name Monetary value, commodity identity and numeric value
+@{
+  */
+struct _gnc_monetary
+{
+  gnc_commodity *commodity;
+  gnc_numeric value;
+};
 
+typedef struct _gnc_monetary gnc_monetary;
+
+/* A list of monetary values.  This could be a hash table, but as currently
+* used it rarely contains more than one or two different commodities so 
+* it doesn't seem worth the trouble. 
+*/
+typedef GList MonetaryList;
+
+/** @name Constructors
+@{
+  Make a gnc_monetary from a gnc_commodity and gnc_numeric */
+  static inline
+  gnc_monetary gnc_monetary_create(gnc_commodity *commod, gnc_numeric val) {
+    gnc_monetary out;
+    out.commodity = commod;
+    out.value = val;
+    return out;
+  }
+  /** @} */
+  
+  /** @name Accessors
+  @{
+    */
+  static inline
+  gnc_commodity * gnc_monetary_commodity(gnc_monetary a) { return a.commodity; }
+  
+  static inline
+  gnc_numeric gnc_monetary_value(gnc_monetary a) { return a.value; }
+  /** @} */
+  
+  /** @name Manipulate MonetaryList lists
+@{
+  */
+
+/** Add a gnc_monetary to the list */
+MonetaryList *gnc_monetary_list_add_monetary(MonetaryList *list, gnc_monetary mon);
+
+/** Add something to the list given a commodity and value */
+static inline
+MonetaryList *gnc_monetary_list_add_value(MonetaryList *list, 
+                                          gnc_commodity *commod, 
+                                          gnc_numeric value)
+{
+  return gnc_monetary_list_add_monetary(list,
+                                        gnc_monetary_create(commod, value));
+}
+
+/** Delete all the zero-value entries from a list */
+MonetaryList *gnc_monetary_list_delete_zeros(MonetaryList *list);
+
+/** Free a monetary list and all the items it points to */
+void gnc_monetary_list_free(MonetaryList *list);
+/** @} */
+
+/** @} */
+
 #endif /* GNC_COMMODITY_H */
 /** @} */
 /** @} */
Index: src/engine/Split.c
===================================================================
--- src/engine/Split.c	(revision 18399)
+++ src/engine/Split.c	(working copy)
@@ -1056,7 +1056,7 @@
    * rate and just return the 'other' split amount.
    */
   txn = xaccSplitGetParent (split);
-  if (txn && gnc_numeric_zero_p (xaccTransGetImbalance (txn))) {
+  if (txn && xaccTransIsBalanced (txn)) {
     const Split *osplit = xaccSplitGetOtherSplit (split);
 
     if (osplit)
@@ -1668,6 +1668,9 @@
   int count, num_splits;
   Split *other = NULL;
   KvpValue *sva;
+  Account *trading_account = NULL;
+  Account *root_account = NULL;
+  gboolean trading_accts;
 
   if (!split) return NULL;
   trans = split->parent;
@@ -1684,16 +1687,20 @@
   return s1;
 #endif
 
+  trading_accts = xaccTransUseTradingAccounts (trans);
   num_splits = xaccTransCountSplits(trans);
   count = num_splits;
   sva = kvp_frame_get_slot (split->inst.kvp_data, "lot-split");
-  if (!sva && (2 != count)) return NULL;
+  if (!sva && !trading_accts && (2 != count)) return NULL;
 
   for (i = 0; i < num_splits; i++) {
       Split *s = xaccTransGetSplit(trans, i);
       if (s == split) { --count; continue; }
       if (kvp_frame_get_slot (s->inst.kvp_data, "lot-split")) 
           { --count; continue; }
+      if (trading_accts && 
+          xaccAccountGetType(xaccSplitGetAccount(s)) == ACCT_TYPE_TRADING)
+          { --count; continue; }
       other = s;
   }
   return (1 == count) ? other : NULL;
Index: src/app-utils/prefs.scm
===================================================================
--- src/app-utils/prefs.scm	(revision 18399)
+++ src/app-utils/prefs.scm	(working copy)
@@ -75,6 +75,7 @@
         (cons ACCT-TYPE-EXPENSE    (N_ "Expense"))
         (cons ACCT-TYPE-PAYABLE    (N_ "Payment"))
         (cons ACCT-TYPE-RECEIVABLE (N_ "Invoice"))
+        (cons ACCT-TYPE-TRADING    (N_ "Decrease"))
         (cons ACCT-TYPE-EQUITY     (N_ "Decrease"))))
 
 (define gnc:*credit-strings*
@@ -91,6 +92,7 @@
         (cons ACCT-TYPE-EXPENSE    (N_ "Rebate"))
         (cons ACCT-TYPE-PAYABLE    (N_ "Bill"))
         (cons ACCT-TYPE-RECEIVABLE (N_ "Payment"))
+        (cons ACCT-TYPE-TRADING    (N_ "Increase"))
         (cons ACCT-TYPE-EQUITY     (N_ "Increase"))))
 
 (define (gnc:get-debit-string type)
