xlwings Functions

  • examples_write_to_sheet()
  • examples_read_from_sheet()
  • example_get_user_input_text()
  • example_get_user_input_range_as_dataframe()
  • example_get_user_input_range_as_array()
  • load_timeseries(kind: str, curve_name: xw.Range, start_date: Optional[datetime], end_date: Optional[datetime], date_format: Optional[str], force_reload: Optional[bool])
  • load_timeseries_excel(curve_name: xw.Range, start_date: Optional[datetime], end_date: Optional[datetime], force_reload: Optional[bool])
  • load_timeseries_volue(curve_name: xw.Range, start_date: Optional[datetime], end_date: Optional[datetime], force_reload: Optional[bool])
  • load_timeseries_datacenter(curve_name: xw.Range, start_date: Optional[datetime], end_date: Optional[datetime], force_reload: Optional[bool])
  • load_timeseries_csv(curve_name: xw.Range, start_date: Optional[datetime], end_date: Optional[datetime], force_reload: Optional[bool])
  • load_timeseries_enmacc(curve_name: xw.Range, start_date: Optional[datetime], end_date: Optional[datetime], force_reload: Optional[bool])
  • load_requests_enmacc()
  • load_concluded_requests_enmacc(concluded_from: datetime, concluded_to: datetime)
  • write_timeseries_to_sheet(rng: xw.Range, n: Optional[int], start_date: Optional[datetime], end_date: Optional[datetime])
  • describe_data(rng: xw.Range)
  • list_cached_sources()
  • clear_cache(return_value_in_cell: Optional[str]) -> str
  • add_price_timeseries(ts1_id: xw.Range, ts2_id: xw.Range, floor: Optional[bool])
  • subtract_price_timeseries(ts1_id: xw.Range, ts2_id: xw.Range, floor: Optional[bool])
  • multiply_price_timeseries(ts1_id: xw.Range, ts2_id: xw.Range)
  • concat_price_timeseries(ts1_id: xw.Range, ts2_id: xw.Range, duplicate_strategy: str)
  • CORREL2(df)

Why is new_df = new_df.sort_index(kind='mergesort') necessary?

Short answer: itโ€™s there to make keep="first" / keep="last" deterministic and time-correct.


๐Ÿ”น What problem it solves

When you do:

new_df = pd.concat([self.df, other.df], axis=0)

the resulting order is:

  • all rows from self.df
  • then all rows from other.df

๐Ÿ‘‰ This is not guaranteed to be time-ordered


๐Ÿ”ฅ Why that matters

Your duplicate handling depends on order:

new_df.index.duplicated(keep="last")

๐Ÿ‘‰ โ€œlastโ€ means:

last in the current row order, not last in time


โŒ Without sorting (buggy behavior)

Imagine:

self.df:
2024-01-02 โ†’ A

other.df:
2024-01-01 โ†’ B
2024-01-02 โ†’ C

After concat:

2024-01-02 โ†’ A
2024-01-01 โ†’ B
2024-01-02 โ†’ C

Now:

keep="last"

keeps C, but:

  • ordering is inconsistent
  • time series is not sorted
  • logic becomes fragile

โœ… With sorting

new_df = new_df.sort_index(kind="mergesort")

Result:

2024-01-01 โ†’ B
2024-01-02 โ†’ A
2024-01-02 โ†’ C

Now:

  • duplicates are grouped
  • โ€œlastโ€ means latest occurrence within same timestamp group
  • behavior is consistent and predictable

๐Ÿ”น Why mergesort specifically?

sort_index(kind="mergesort")

Because:

  • โœ… stable sort
  • preserves original order within equal indices

๐Ÿ‘‰ This is critical:

If two rows share the same timestamp:

  • their relative order (self vs other) is preserved
  • so keep="last" reliably prefers other

โ— Without stable sort (e.g. quicksort)

Pandas might reorder equal timestamps unpredictably:

๐Ÿ‘‰ then:

  • sometimes self wins
  • sometimes other wins ๐Ÿ’ฅ exactly the issue you described earlier

๐Ÿ”‘ Key insight

This line ensures:

โ€œFor equal timestamps, preserve concat order โ†’ so other overwrites selfโ€


๐Ÿง  Summary

new_df = new_df.sort_index(kind="mergesort")

is necessary because it:

  1. Sorts time series chronologically
  2. Groups duplicate timestamps together
  3. Preserves order between duplicates (critical)
  4. Makes keep="last" deterministic

๐Ÿš€ Alternative (if you want to avoid sorting dependency)

If your intent is strictly:

โ€œother overrides selfโ€

You could skip sorting entirely and do:

new_df = self.df.copy()
new_df.update(other.df)

But:

  • โŒ doesnโ€™t handle non-overlapping rows the same way
  • โŒ not equivalent to concat